Removed client

This commit is contained in:
Tracker-Friendly 2024-03-12 18:37:14 +00:00
parent b0c2d119f6
commit 913a645fea
73 changed files with 7 additions and 9091 deletions

59
main
View File

@ -8,7 +8,7 @@ import asyncio
from hypercorn.config import Config
from hypercorn.asyncio import serve
from werkzeug.security import generate_password_hash, check_password_hash
from quart import Quart, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request
from quart import Quart, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request
# Parse configuration file, and check if anything is wrong with it
if not os.path.exists("config.ini"):
@ -107,54 +107,6 @@ async def add_cors_headers(response):
response.headers.add("Access-Control-Allow-Methods", "*")
return response
# Main page
@app.route("/index.html")
async def mainrdir():
return redirect("/", code=302)
@app.route("/")
async def main():
return await render_template("main.html")
# Homeserver changer
@app.route("/homeserver/index.html")
async def homeserverrdir():
return redirect("/", code=302)
@app.route("/homeserver")
async def homeserver():
return await render_template("homeserver.html")
# Web app
@app.route("/app/index.html")
async def apprdir():
return redirect("/app", code=302)
@app.route("/app")
async def webapp():
return await render_template("app.html")
# Login and signup
@app.route("/signup/index.html")
async def signuprdir():
return redirect("/signup", code=302)
@app.route("/signup")
async def signup():
return await render_template("signup.html")
@app.route("/login/index.html")
async def loginrdir():
return redirect("/login", code=302)
@app.route("/login")
async def login():
return await render_template("login.html")
# Privacy policy
@app.route("/privacy/index.html")
async def privacyrdir():
return redirect("/privacy", code=302)
@app.route("/privacy")
async def privacy():
return await render_template("privacy.html")
# API
@app.route("/api/version", methods=("GET", "POST"))
async def apiversion():
return "Burgernotes Version 1.2"
@ -535,20 +487,13 @@ def listusers(secretkey):
else:
return redirect("/")
@app.route("/logout/index.html")
async def logoutrdir():
return redirect("/logout", code=302)
@app.route("/logout")
async def apilogout():
return await render_template("logout.html")
@app.errorhandler(500)
async def burger(e):
return {}, 500
@app.errorhandler(404)
async def burger(e):
return await render_template("error.html", errorCode=404, errorMessage="Page not found"), 404
return {}, 404
# Start server
hypercornconfig = Config()

File diff suppressed because one or more lines are too long

View File

@ -1,695 +0,0 @@
@import url("../fonts/inter.css");
:root {
--contrast: #eee;
--contrast2: #fff;
--invertdm: 0%;
--bar: #f4f4f4;
--editor: #ffffff;
--text-color: #000000;
--border-color: #dadada;
--theme-color: #157efb;
--theme-text-color: #ffffff;
--exit-color: #e9e9e9;
--session-color: #f4f4f4;
--note-button: #ffffff;
--note-button-text-color: #ffffff;
--unselected-note-button-text-color: #000000;
--option-background: #ffffff;
--invert: 100%;
--bottomBarHover: #e4e4e4;
}
/* dark mode */
@media (prefers-color-scheme: dark) {
:root {
--invertdm: 100%;
--contrast: #2d2f21;
--contrast2: #2d2f21;
--bar: #2d2f31;
--editor: #202124;
--text-color: #ffffff;
--border-color: #393b3d;
--theme-color: #157efb;
--theme-text-color: #ffffff;
--exit-color: #454649;
--session-color: #2d2f31;
--note-button: #202124;
--note-button-text-color: #ffffff;
--unselected-note-button-text-color: #ffffff;
--option-background: #202124;
--invert: 100%;
--bottomBarHover: #e4e4e4;
}
.startDiv p {
color: white !important;
}
.topBar p {
color: white !important;
}
.newNote {
color: white !important;
}
.newNote img {
filter: invert(100%);
}
#errorDiv p {
color: white !important;
}
.optionsCoverDiv p {
color: white !important;
}
.burgerSession img {
filter: invert(100%) !important;
}
.links a {
color: white !important;
}
.inoutdiv p {
color: white !important;
}
.inoutdiv a {
color: #969696 !important;
}
.inoutdiv input {
color: white;
background-color: var(--editor);
}
.flathubLogo {
filter: invert(100%);
}
.feature {
background-color: rgba(0, 0, 0, 0) !important;
color: var(--text-color);
}
.mainDiv .yellow {
border-color: #e9e98d !important;
}
.mainDiv .green {
border-color: #a9f9a9 !important;
}
}
p,
li,
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--text-color);
white-space: break-spaces;
}
h7 {
display: block;
font-size: 20px;
margin-top: 0.67em;
margin-bottom: 0.67em;
margin-left: 0;
margin-right: 0;
}
body {
margin: 0;
background-color: var(--editor);
font-family: "Inter", sans-serif;
}
.hiddenButton {
right: 0px;
position: fixed;
background-color: var(--editor);
color: var(--editor);
padding: 20px;
}
/* Web app */
.topBar {
position: fixed;
width: 100%;
height: 50px;
background-color: var(--bar);
border: solid;
border-color: var(--border-color);
border-width: 0px;
border-bottom-width: 1px;
}
.bottomBar {
position: fixed;
width: 100%;
height: 29px;
bottom: 0;
background-color: var(--bar);
border: solid;
border-color: var(--border-color);
border-width: 0px;
border-top-width: 1px;
display: flex;
}
.bottomBar button {
background-color: rgba(0, 0, 0, 0);
color: var(--text-color);
height: 100%;
border: none;
font-size: 14px;
padding-left: 7.5px;
padding-right: 7.5px;
}
.bottomBar .removeButton {
filter: invert(var(--invertdm));
padding-left: 17.5px;
padding-right: 17.5px;
background-image: url("../../static/svg/delete.svg");
background-position: center;
background-repeat: no-repeat;
background-size: 55%;
}
.bottomBar .textManipulator {
margin-left: auto;
}
.bottomBar button:hover {
background-color: var(--bottomBarHover);
}
.bottomBar .right {
float: right;
}
.burgerDropdown {
position: fixed;
z-index: 2;
left: 7px;
top: 30px;
width: 160px;
height: 90px;
background-color: var(--bar);
border: solid;
border-color: var(--border-color);
border-width: 1px;
border-radius: 8px;
}
.burgerDropdown a {
position: absolute;
width: calc(100% - 14px - 4px - 7px);
color: var(--text-color);
background-color: #ffffff;
height: 35px;
line-height: 35px;
margin: 7px;
padding-left: 7px;
border: solid;
border-color: var(--border-color);
border-width: 1px;
border-radius: 8px;
font-size: 15px;
text-decoration: none;
}
.topBar p {
display: inline-block;
}
.topBar .logo {
padding-left: 12px;
}
.topBar .usernameBox {
text-align: right;
position: absolute;
cursor: pointer;
right: 12px;
}
.notesBar {
position: fixed;
width: 180px;
top: 50px;
height: calc(100% - 50px - 30px - 1px);
background-color: var(--bar);
border: solid;
border-color: var(--border-color);
border-width: 0px;
border-right-width: 1px;
border-top-width: 1px;
}
.notesDiv {
height: calc(100% - 50px);
overflow-y: scroll;
}
.notesBar .noteButton, .notesBar .loadingStuff {
width: calc(100% - 7px - 7px - 3.5px);
height: 35px;
line-height: 0px;
padding: 10px;
margin: 5px;
margin-bottom: 0;
background-color: var(--note-button);
color: var(--unselected-note-button-text-color);
border: none;
border-radius: 8px;
border: solid;
border-color: var(--border-color);
border-width: 1px;
font-size: 15px;
text-align: left;
cursor: pointer;
}
.notesBar .loadingStuff {
border: none;
background:
linear-gradient(0.25turn, transparent, var(--contrast2), transparent),
linear-gradient(var(--contrast), var(--contrast)),
radial-gradient(38px circle at 19px 19px, #eee 50%, transparent 51%),
linear-gradient(var(--contrast), var(--contrast));
background-repeat: no-repeat;
background-size: 315px 250px, 315px 180px, 100px 100px, 225px 30px;
background-position: -315px 0, 0 0, 0px 190px, 50px 195px;
animation: loading 1.5s infinite;
}
@keyframes loading {
to {
background-position: 315px 0, 0 0, 0 190px, 50px 195px;
}
}
.notesBar .selected {
background-color: var(--theme-color) !important;
border: none;
color: var(--note-button-text-color);
}
.notesBar .newNote {
height: 41px;
line-height: 41px;
width: 100%;
text-align: left;
background-color: rgba(0, 0, 0, 0);
border: none;
font-size: 16px;
margin-bottom: 5px;
cursor: pointer;
}
.notesBar .newNote img {
height: 32px;
padding-right: 5px;
transform: translateY(30%);
}
.noteBox {
resize: none;
position: fixed;
right: 0;
top: 55px;
padding: 4px;
border: none;
font-size: 16px;
color: var(--text-color);
background-color: var(--editor);
width: calc(100% - 180px - 7px - 6px);
height: calc(100% - 50px - 6px - 8px - 30px);
font-family: "Inter", sans-serif;
}
.noteBox:focus {
outline: none;
}
.optionsCoverDiv {
position: fixed;
width: 100%;
height: 100%;
z-index: 2;
background-color: rgba(0, 0, 0, 0.7);
transition: opacity 1s;
}
.optionsDiv {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
position: fixed;
background-color: var(--option-background);
padding: 10px;
color: var(--text-color);
border-radius: 8px;
min-width: 300px;
z-index: 3;
}
.optionsDiv button {
width: 100%;
padding: 10px;
padding-bottom: 13px;
margin-right: 5px;
margin-bottom: 7px;
padding-left: 15px;
padding-right: 15px;
color: var(--theme-text-color);
border: none;
text-decoration: none;
background-color: var(--theme-color);
border-radius: 8px;
cursor: pointer;
}
.optionsDiv .normalButton {
width: auto;
margin-bottom: 0px;
}
.optionsDiv .lastButton {
margin-bottom: 0px;
}
.optionsDiv input {
width: calc(100% - 12px);
height: 25px;
background-color: #ffffff;
padding-left: 5px;
padding-right: 5px;
margin-bottom: 7px;
border: solid;
border-color: var(--border-color);
border-width: 1px;
border-radius: 8px;
}
.optionsDiv .mfacheckbox {
display: inline;
margin: 0;
margin-left: 5px;
margin-bottom: 12px;
padding: 0;
height: 17px;
width: 17px;
}
.optionsDiv input:focus {
outline: 0;
border-color: var(--theme-color);
}
.optionsDiv code {
padding: 7px;
font-size: 14px;
border-radius: 8px;
background-color: var(--session-color);
}
.optionsDiv progress {
width: 100%;
background-color: var(--session-color);
border: none;
border-radius: 99px;
height: 7px;
}
.optionsDiv progress::-moz-progress-bar {
background: var(--theme-color);
}
.optionsDiv progresss::-webkit-progress-value {
background: var(--theme-color);
}
.optionsDiv .exit {
position: absolute;
right: 5px;
width: 40px;
height: 40px;
font-size: 16px;
background-color: var(--exit-color);
color: var(--text-color);
border-radius: 100%;
}
.optionsDiv img {
height: 18px;
padding-right: 5px;
filter: invert(var(--invert));
transform: translateY(3.25px);
}
.optionsDiv .section {
width: 100%;
height: 1px;
background-color: var(--border-color);
margin-top: 2px;
margin-bottom: 10px;
}
.sessionDiv {
max-height: 255px;
overflow-y: auto;
}
.sessionDiv div {
position: relative;
background-color: var(--session-color);
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 {
margin: 10%;
padding: 30px;
border-radius: 25px;
border: solid 1px var(--border-color);
background-color: var(--bar);
}
.inoutdiv input {
width: calc(100% - 120px);
height: 30px;
margin-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
border: solid;
border-color: var(--border-color);
border-width: 1px;
border-radius: 8px;
}
.inoutdiv button {
background-color: var(--theme-color);
color: white;
padding: 10px;
margin-right: 5px;
padding-left: 20px;
padding-right: 20px;
border: none;
border-radius: 8px;
font-size: 14px;
}
.inoutdiv a {
color: grey;
text-align: center;
}
.hidden {
display: none !important;
}
.w100 {
font-weight: 300;
}
.w200 {
font-weight: 300;
}
.w300 {
font-weight: 300;
}
.w400 {
font-weight: 400;
}
.w500 {
font-weight: 500;
}
.w600 {
font-weight: 600;
}
.w700 {
font-weight: 700;
}
.w800 {
font-weight: 800;
}
.w900 {
font-weight: 900;
}
.alertDiv {
position: fixed;
margin: 0;
width: 100%;
background-color: #ffffeb;
height: 25px;
z-index: 9999;
top: 0;
}
/* main */
.mainDiv {
text-align: center;
}
.startDiv {
text-align: left;
margin-top: 8vh;
margin-left: 7vh;
display: flex;
flex-direction: column;
}
.startDiv h1 {
margin: 0;
}
.mainDiv a {
padding: 15px;
padding-left: 20px;
padding-right: 20px;
margin-right: auto;
color: white;
text-decoration: none;
background-color: var(--theme-color);
border-radius: 8px;
}
.mainDiv .feature {
width: calc(100% - 7vh - 7vh - 3.5vh);
margin-bottom: 10px;
margin-left: 7vh;
margin-right: 7vh;
padding-left: 10px;
padding-right: 10px;
border: solid;
border-radius: 8px;
border-width: 1px;
border-color: var(--border-color);
padding-top: 15px;
padding-bottom: 15px;
font-size: 17px;
padding-bottom: 30px;
}
.mainDiv .green {
background-color: #ebffeb;
}
.mainDiv .yellow {
background-color: #ffffeb;
}
.links {
text-align: center;
padding: 10px;
}
.links a {
margin-left: 5px;
text-decoration: none;
background-color: var(--bar);
color: var(--text-color);
padding: 10px;
padding-top: 2.5px;
margin-bottom: 10px;
border-radius: 10px;
transition: background-color .2s;
display: inline-block;
}
.links a:hover {
background-color: var(--editor);
}
.links a img {
transform: translateY(5px);
padding-right: 10px;
filter: invert(var(--invertdm));
}
.links a:hover {
text-decoration: dashed;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,57 +0,0 @@
/* Variable fonts usage:
:root { font-family: "Inter", sans-serif; }
@supports (font-variation-settings: normal) {
:root { font-family: "InterVariable", sans-serif; font-optical-sizing: auto; }
} */
@font-face {
font-family: InterVariable;
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("InterVariable.woff2") format("woff2");
}
@font-face {
font-family: InterVariable;
font-style: italic;
font-weight: 100 900;
font-display: swap;
src: url("InterVariable-Italic.woff2") format("woff2");
}
/* static fonts */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100; font-display: swap; src: url("Inter-Thin.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 100; font-display: swap; src: url("Inter-ThinItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 200; font-display: swap; src: url("Inter-ExtraLight.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 200; font-display: swap; src: url("Inter-ExtraLightItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 300; font-display: swap; src: url("Inter-Light.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 300; font-display: swap; src: url("Inter-LightItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("Inter-Regular.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 400; font-display: swap; src: url("Inter-Italic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("Inter-Medium.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 500; font-display: swap; src: url("Inter-MediumItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("Inter-SemiBold.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 600; font-display: swap; src: url("Inter-SemiBoldItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("Inter-Bold.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 700; font-display: swap; src: url("Inter-BoldItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 800; font-display: swap; src: url("Inter-ExtraBold.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 800; font-display: swap; src: url("Inter-ExtraBoldItalic.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 900; font-display: swap; src: url("Inter-Black.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 900; font-display: swap; src: url("Inter-BlackItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 100; font-display: swap; src: url("InterDisplay-Thin.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 100; font-display: swap; src: url("InterDisplay-ThinItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 200; font-display: swap; src: url("InterDisplay-ExtraLight.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 200; font-display: swap; src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 300; font-display: swap; src: url("InterDisplay-Light.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 300; font-display: swap; src: url("InterDisplay-LightItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 400; font-display: swap; src: url("InterDisplay-Regular.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 400; font-display: swap; src: url("InterDisplay-Italic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 500; font-display: swap; src: url("InterDisplay-Medium.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 500; font-display: swap; src: url("InterDisplay-MediumItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 600; font-display: swap; src: url("InterDisplay-SemiBold.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 600; font-display: swap; src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 700; font-display: swap; src: url("InterDisplay-Bold.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 700; font-display: swap; src: url("InterDisplay-BoldItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 800; font-display: swap; src: url("InterDisplay-ExtraBold.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 800; font-display: swap; src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: normal; font-weight: 900; font-display: swap; src: url("InterDisplay-Black.woff2") format("woff2"); }
@font-face { font-family: "InterDisplay"; font-style: italic; font-weight: 900; font-display: swap; src: url("InterDisplay-BlackItalic.woff2") format("woff2"); }

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,49 +0,0 @@
let homeserverBox = document.getElementById("homeserverBox")
let statusBox = document.getElementById("statusBox")
let changeButton = document.getElementById("changeButton")
function showElements(yesorno) {
if (!yesorno) {
homeserverBox.classList.add("hidden")
changeButton.classList.add("hidden")
}
else {
homeserverBox.classList.remove("hidden")
changeButton.classList.remove("hidden")
}
}
changeButton.addEventListener("click", (event) => {
async function doStuff() {
let remote = homeserverBox.value
if (remote == "") {
statusBox.innerText = "A homeserver is required!"
return
}
showElements(false)
statusBox.innerText = "Connecting to homeserver..."
fetch(remote + "/api/version")
.then((response) => response)
.then((response) => {
async function doStuff() {
if (response.status == 200) {
localStorage.setItem("homeserverURL", remote)
window.location.href = document.referrer;
}
else if (response.status == 404) {
statusBox.innerText = "Not a valid homeserver!"
}
else {
statusBox.innerText = "Something went wrong!"
showElements(true)
}
}
doStuff()
});
}
doStuff()
});

View File

@ -1,199 +0,0 @@
if (localStorage.getItem("DONOTSHARE-secretkey") !== null) {
window.location.replace("../app/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
if (localStorage.getItem("DONOTSHARE-password") !== null) {
window.location.replace("../app/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
let remote = localStorage.getItem("homeserverURL")
if (remote == null) {
localStorage.setItem("homeserverURL", "https://notes.hectabit.org")
remote = "https://notes.hectabit.org"
}
let usernameBox = document.getElementById("usernameBox")
let passwordBox = document.getElementById("passwordBox")
let statusBox = document.getElementById("statusBox")
let signupButton = document.getElementById("signupButton")
let inputNameBox = document.getElementById("inputNameBox")
let backButton = document.getElementById("backButton")
usernameBox.classList.remove("hidden")
inputNameBox.innerText = "Username:"
let currentInputType = 0
function showInput(inputType) {
if (inputType == 0) {
usernameBox.classList.remove("hidden")
passwordBox.classList.add("hidden")
backButton.classList.add("hidden")
inputNameBox.innerText = "Username:"
statusBox.innerText = "Login to your Burgernotes account!"
currentInputType = 0
} else if (inputType == 1) {
usernameBox.classList.add("hidden")
passwordBox.classList.remove("hidden")
backButton.classList.remove("hidden")
inputNameBox.innerText = "Password:"
currentInputType = 1
} else if (inputType == 2) {
usernameBox.classList.add("hidden")
passwordBox.classList.add("hidden")
signupButton.classList.add("hidden")
backButton.classList.add("hidden")
inputNameBox.classList.add("hidden")
inputNameBox.innerText = "Password:"
currentInputType = 2
}
}
function showElements(yesorno) {
if (!yesorno) {
usernameBox.classList.add("hidden")
passwordBox.classList.add("hidden")
signupButton.classList.add("hidden")
backButton.classList.add("hidden")
inputNameBox.classList.add("hidden")
showInput(currentInputType)
}
else {
usernameBox.classList.remove("hidden")
passwordBox.classList.remove("hidden")
signupButton.classList.remove("hidden")
backButton.classList.remove("hidden")
inputNameBox.classList.remove("hidden")
showInput(currentInputType)
}
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("homeserver").innerText = "Your homeserver is: " + remote + ". "
});
signupButton.addEventListener("click", (event) => {
if (passwordBox.classList.contains("hidden")) {
if (usernameBox.value == "") {
statusBox.innerText = "A username is required!"
return
} else {
statusBox.innerText = "Welcome back, " + usernameBox.value + "!"
}
showInput(1)
} else {
async function doStuff() {
let username = usernameBox.value
let password = passwordBox.value
if (password == "") {
statusBox.innerText = "A password is required!"
return
}
showInput(2)
showElements(true)
statusBox.innerText = "Signing in..."
async function hashpassold(pass) {
const key = await hashwasm.argon2id({
password: pass,
salt: await hashwasm.sha512(pass),
parallelism: 1,
iterations: 256,
memorySize: 512,
hashLength: 32,
outputType: "encoded"
});
return key
};
async function hashpass(pass) {
let key = pass
for (let i = 0; i < 128; i++) {
key = await hashwasm.sha3(key)
}
return key
};
fetch(remote + "/api/login", {
method: "POST",
body: JSON.stringify({
username: username,
password: await hashpass(password),
passwordchange: "no",
newpass: "null"
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => response)
.then((response) => {
async function doStuff() {
let responseData = await response.json()
if (response.status == 200) {
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
localStorage.setItem("DONOTSHARE-password", await hashwasm.sha512(password))
window.location.href = "../app/index.html"
}
else if (response.status == 401) {
console.log("Trying oldhash")
fetch(remote + "/api/login", {
method: "POST",
body: JSON.stringify({
username: username,
password: await hashpassold(password),
passwordchange: "yes",
newpass: await hashpass(password)
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => response)
.then((response) => {
async function doStuff2() {
let responseData = await response.json()
if (response.status == 200) {
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
localStorage.setItem("DONOTSHARE-password", await hashwasm.sha512(password))
window.location.href = "../app/index.html"
}
else if (response.status == 401) {
statusBox.innerText = "Wrong username or password..."
showInput(1)
showElements(true)
}
else {
statusBox.innerText = "Something went wrong! (error code: " + response.status + ")"
showInput(1)
showElements(true)
}
}
doStuff2()
});
}
else {
statusBox.innerText = "Something went wrong! (error code: " + response.status + ")"
showInput(1)
showElements(true)
}
}
doStuff()
});
}
doStuff()
}
});
backButton.addEventListener("click", (event) => {
showInput(0)
});
showInput(0)

View File

@ -1,642 +0,0 @@
if (localStorage.getItem("DONOTSHARE-secretkey") === null) {
window.location.replace("../login/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
if (localStorage.getItem("DONOTSHARE-password") === null) {
window.location.replace("../login/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
if (localStorage.getItem("CACHE-username") !== null) {
document.getElementById("usernameBox").innerText = localStorage.getItem("CACHE-username")
}
let remote = localStorage.getItem("homeserverURL")
if (remote == null) {
localStorage.setItem("homeserverURL", "https://notes.hectabit.org")
remote = "https://notes.hectabit.org"
}
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")
let usernameBox = document.getElementById("usernameBox")
let optionsCoverDiv = document.getElementById("optionsCoverDiv")
let optionsDiv = document.getElementById("optionsDiv")
let errorDiv = document.getElementById("errorDiv")
let errorMessageThing = document.getElementById("errorMessageThing")
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 mfaDiv = document.getElementById("mfaDiv")
let deleteMyAccountButton = document.getElementById("deleteMyAccountButton")
let storageThing = document.getElementById("storageThing")
let storageProgressThing = document.getElementById("storageProgressThing")
let usernameThing = document.getElementById("usernameThing")
let logOutButton = document.getElementById("logOutButton")
let notesBar = document.getElementById("notesBar")
let notesDiv = document.getElementById("notesDiv")
let newNote = document.getElementById("newNote")
let noteBox = document.getElementById("noteBox")
let loadingStuff = document.getElementById("loadingStuff")
let burgerButton = document.getElementById("burgerButton")
let exportNotesButton = document.getElementById("exportNotesButton")
let selectedNote = 0
let timer
let waitTime = 400
if (/Android|iPhone|iPod/i.test(navigator.userAgent)) {
noteBox.style.width = "10px";
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;
touchstartY = event.changedTouches[0].screenY;
}, false);
notesBar.addEventListener("touchend", function (event) {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
handleGesture();
}, false);
noteBox.addEventListener("touchstart", function (event) {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
noteBox.addEventListener("touchend", function (event) {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
handleGesture();
}, false);
function handleGesture() {
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 - 75) {
noteBox.style.width = "calc(100% - 30px)";
notesBar.style.width = "10px"
if (selectedNote != 0) {
noteBox.readOnly = false
}
notesDiv.classList.add("hidden")
noteBox.classList.remove("hidden")
newNote.classList.add("hidden")
}
}
}
noteBox.value = ""
noteBox.readOnly = true
let noteCount = 0
function displayError(message) {
errorDiv.classList.remove("hidden")
optionsCoverDiv.classList.remove("hidden")
errorMessageThing.innerHTML = message
}
closeErrorButton.addEventListener("click", (event) => {
errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden")
});
function displayPrompt(message, placeholdertext, callback) {
errorMessageThing.innerText = message
errorInput.value = ""
errorInput.placeholder = placeholdertext
closeErrorButton.addEventListener("click", (event) => {
if (callback) {
callback(errorInput.value)
callback = undefined
}
});
errorInput.addEventListener("keyup", (event) => {
if (event.key == "Enter") {
callback(errorInput.value)
callback = undefined
errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden")
errorInput.classList.add("hidden")
cancelErrorButton.classList.add("hidden")
}
});
cancelErrorButton.addEventListener("click", (event) => {
callback = undefined
errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden")
errorInput.classList.add("hidden")
cancelErrorButton.classList.add("hidden")
});
errorDiv.classList.remove("hidden")
optionsCoverDiv.classList.remove("hidden")
errorInput.classList.remove("hidden")
cancelErrorButton.classList.remove("hidden")
errorInput.focus()
}
closeErrorButton.addEventListener("click", (event) => {
errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden")
errorInput.classList.add("hidden")
cancelErrorButton.classList.add("hidden")
});
function updateFont() {
let currentFontSize = localStorage.getItem("SETTING-fontsize")
noteBox.style.fontSize = currentFontSize + "px"
textSizeBox.innerText = currentFontSize + "px"
}
if (localStorage.getItem("SETTING-fontsize") === null) {
localStorage.setItem("SETTING-fontsize", "16")
updateFont()
} else {
updateFont()
}
textPlusBox.addEventListener("click", (event) => {
localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) + Number(1)))
updateFont()
});
textMinusBox.addEventListener("click", (event) => {
localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) - Number(1)))
updateFont()
});
function truncateString(str, num) {
if (str.length > num) {
return str.slice(0, num) + "..";
} else {
return str;
}
}
function updateUserInfo() {
fetch(remote + "/api/userinfo", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.catch((error) => {
noteBox.readOnly = true
noteBox.value = ""
noteBox.placeholder = "Failed to connect to the server.\nPlease check your internet connection."
})
.then((response) => {
async function doStuff() {
if (response.status == 500) {
displayError("Something went wrong! Signing you out..")
closeErrorButton.classList.add("hidden")
usernameBox.innerText = ""
setTimeout(function () {
window.location.replace("../logout/index.html")
}, 2500);
} else {
let responseData = await response.json()
usernameBox.innerText = responseData["username"]
usernameThing.innerText = "Username: " + 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"]
localStorage.setItem("CACHE-username", responseData["username"])
}
}
doStuff()
});
}
usernameBox.addEventListener("click", (event) => {
optionsCoverDiv.classList.remove("hidden")
optionsDiv.classList.remove("hidden")
updateUserInfo()
});
logOutButton.addEventListener("click", (event) => {
window.location.replace("../logout/index.html")
});
exitThing.addEventListener("click", (event) => {
optionsDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden")
});
deleteMyAccountButton.addEventListener("click", (event) => {
if (confirm("Are you REALLY sure that you want to delete your account? There's no going back!") == true) {
fetch(remote + "/api/deleteaccount", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
if (response.status == 200) {
window.location.href = "../logout/index.html"
} else {
displayError("Failed to delete account (HTTP error code " + response.status + ")")
}
})
}
});
sessionManagerButton.addEventListener("click", (event) => {
optionsDiv.classList.add("hidden")
sessionManagerDiv.classList.remove("hidden")
fetch(remote + "/api/sessions/list", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.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.innerText = "(current) " + responseData[i]["device"]
} else {
sessionText.innerText = responseData[i]["device"]
}
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") || ua.include("iPod"))) {
sessionImage.src = "/static/svg/device_smartphone.svg"
}
sessionRemoveButton.addEventListener("click", (event) => {
fetch(remote + "/api/sessions/remove", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
sessionId: responseData[i]["id"]
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
if (responseData[i]["thisSession"] == true) {
window.location.replace("../logout/index.html")
}
});
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()
function updateWordCount() {
let wordCount = noteBox.value.split(" ").length
if (wordCount == 1) {
wordCount = 0
}
wordCountBox.innerText = wordCount + " words"
}
function selectNote(nameithink) {
document.querySelectorAll(".noteButton").forEach((el) => el.classList.remove("selected"));
let thingArray = Array.from(document.querySelectorAll(".noteButton")).find(el => el.id == nameithink);
thingArray.classList.add("selected")
fetch(remote + "/api/readnote", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
noteId: nameithink,
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.catch((error) => {
noteBox.readOnly = true
noteBox.value = ""
noteBox.placeholder = ""
displayError("Something went wrong... Please try again later!")
})
.then((response) => {
selectedNote = nameithink
noteBox.readOnly = false
noteBox.placeholder = "Type something!"
async function doStuff() {
let responseData = await response.json()
let bytes = CryptoJS.AES.decrypt(responseData["content"], password);
let originalText = bytes.toString(CryptoJS.enc.Utf8);
noteBox.value = originalText
updateWordCount()
noteBox.addEventListener("input", (event) => {
updateWordCount()
clearTimeout(timer);
timer = setTimeout(() => {
let encryptedTitle = "New note"
if (noteBox.value.substring(0, noteBox.value.indexOf("\n")) != "") {
let firstTitle = noteBox.value.substring(0, noteBox.value.indexOf("\n"));
document.getElementById(nameithink).innerText = firstTitle
encryptedTitle = CryptoJS.AES.encrypt(firstTitle, password).toString();
}
let encryptedText = CryptoJS.AES.encrypt(noteBox.value, password).toString();
if (selectedNote == nameithink) {
fetch(remote + "/api/editnote", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
noteId: nameithink,
content: encryptedText,
title: encryptedTitle
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
if (response.status == 418) {
displayError("You've ran out of storage... Changes will not be saved until you free up storage!")
}
})
.catch((error) => {
displayError("Failed to save changes, please try again later...")
})
}
}, waitTime);
});
}
doStuff()
});
}
function updateNotes() {
fetch(remote + "/api/listnotes", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
async function doStuff() {
document.querySelectorAll(".noteButton").forEach((el) => el.remove());
noteBox.readOnly = true
selectedNote = 0
noteBox.placeholder = ""
noteBox.value = ""
clearTimeout(timer)
updateWordCount()
let responseData = await response.json()
for (let i in responseData) {
let noteButton = document.createElement("button");
noteButton.classList.add("noteButton")
notesDiv.append(noteButton)
let bytes = CryptoJS.AES.decrypt(responseData[i]["title"], password);
let originalTitle = bytes.toString(CryptoJS.enc.Utf8);
noteButton.id = responseData[i]["id"]
noteButton.innerText = truncateString(originalTitle, 15)
noteButton.addEventListener("click", (event) => {
if (event.ctrlKey) {
fetch(remote + "/api/removenote", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
noteId: responseData[i]["id"]
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
updateNotes()
})
.catch((error) => {
displayError("Something went wrong! Please try again later...")
})
} else {
selectNote(responseData[i]["id"])
}
});
}
document.querySelectorAll(".loadingStuff").forEach((el) => el.remove());
}
doStuff()
});
}
updateNotes()
newNote.addEventListener("click", (event) => {
let noteName = "New note"
let encryptedName = CryptoJS.AES.encrypt(noteName, password).toString();
fetch(remote + "/api/newnote", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
noteName: encryptedName,
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.catch((error) => {
displayError("Failed to create new note, please try again later...")
})
.then((response) => {
if (response.status !== 200) {
updateNotes()
displayError("Failed to create new note (HTTP error code " + response.status + ")")
} else {
updateNotes()
}
});
});
function downloadObjectAsJson(exportObj, exportName) {
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
var downloadAnchorNode = document.createElement("a");
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", exportName + ".json");
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
}
function exportNotes() {
let noteExport = []
fetch(remote + "/api/exportnotes", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey
}),
headers: {
"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 bytes = CryptoJS.AES.decrypt(responseData[i]["title"], password);
let originalTitle = bytes.toString(CryptoJS.enc.Utf8);
responseData[i]["title"] = originalTitle
let bytesd = CryptoJS.AES.decrypt(responseData[i]["content"], password);
let originalContent = bytesd.toString(CryptoJS.enc.Utf8);
responseData[i]["content"] = originalContent
}
let jsonString = JSON.parse(JSON.stringify(responseData))
exportNotesButton.innerText = "Export notes"
downloadObjectAsJson(jsonString, "data")
optionsDiv.classList.add("hidden")
displayError("Exported notes!")
}
doStuff()
})
}
function isFirstTimeVisitor() {
if (document.cookie.indexOf("visited=true") !== -1) {
return false;
} else {
var expirationDate = new Date();
expirationDate.setFullYear(expirationDate.getFullYear() + 1);
document.cookie = "visited=true; expires=" + expirationDate.toUTCString() + "; path=/; SameSite=strict";
return true;
}
}
function firstNewVersion() {
if (document.cookie.indexOf("version=1.1") !== -1) {
return false;
} else {
var expirationDate = new Date();
expirationDate.setFullYear(expirationDate.getFullYear() + 1);
document.cookie = "version=1.1; expires=" + expirationDate.toUTCString() + "; path=/; SameSite=strict";
return true;
}
}
exportNotesButton.addEventListener("click", (event) => {
exportNotesButton.innerText = "Downloading..."
exportNotes()
});
removeBox.addEventListener("click", (event) => {
if (selectedNote == 0) {
displayError("You need to select a note first!")
} else {
fetch(remote + "/api/removenote", {
method: "POST",
body: JSON.stringify({
secretKey: secretkey,
noteId: selectedNote
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => {
updateNotes()
})
.catch((error) => {
displayError("Something went wrong! Please try again later...")
})
}
});
if (isFirstTimeVisitor() && /Android|iPhone|iPod/i.test(navigator.userAgent)) {
displayError("To use Burgernotes:\n Swipe Right on a note to open it\n Swipe left in the text boxes to return to notes\n Click on a note to highlight it")
}
if (firstNewVersion()) {
displayError("What's new in Burgernotes 1.1?\n\nNote titles are now the first line of a note \(will not break compatibility with older notes\)\nIntroduced improved login screen\nNote titles now scroll correctly")
}

View File

@ -1,109 +0,0 @@
if (localStorage.getItem("DONOTSHARE-secretkey") !== null) {
window.location.replace("../app/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
if (localStorage.getItem("DONOTSHARE-password") !== null) {
window.location.replace("../app/index.html")
document.body.innerHTML = "Redirecting..."
throw new Error();
}
let remote = localStorage.getItem("homeserverURL")
if (remote == null) {
localStorage.setItem("homeserverURL", "https://notes.hectabit.org")
remote = "https://notes.hectabit.org"
}
let usernameBox = document.getElementById("usernameBox")
let passwordBox = document.getElementById("passwordBox")
let statusBox = document.getElementById("statusBox")
let signupButton = document.getElementById("signupButton")
function showElements(yesorno) {
if (!yesorno) {
usernameBox.classList.add("hidden")
passwordBox.classList.add("hidden")
signupButton.classList.add("hidden")
}
else {
usernameBox.classList.remove("hidden")
passwordBox.classList.remove("hidden")
signupButton.classList.remove("hidden")
}
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("homeserver").innerText = "Your homeserver is: " + remote + ". "
});
signupButton.addEventListener("click", (event) => {
async function doStuff() {
let username = usernameBox.value
let password = passwordBox.value
if (username == "") {
statusBox.innerText = "A username is required!"
return
}
if ((username).length > 20) {
statusBox.innerText = "Username cannot be more than 20 characters!"
return
}
if (password == "") {
statusBox.innerText = "A password is required!"
return
}
if ((password).length < 8) {
statusBox.innerText = "8 or more characters are required!"
return
}
showElements(false)
statusBox.innerText = "Creating account, please hold on..."
async function hashpass(pass) {
let key = pass
for (let i = 0; i < 128; i++) {
key = await hashwasm.sha3(key)
}
return key
};
fetch(remote + "/api/signup", {
method: "POST",
body: JSON.stringify({
username: username,
password: await hashpass(password)
}),
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then((response) => response)
.then((response) => {
async function doStuff() {
let responseData = await response.json()
if (response.status == 200) {
statusBox.innerText == "redirecting.."
localStorage.setItem("DONOTSHARE-secretkey", responseData["key"])
localStorage.setItem("DONOTSHARE-password", await hashwasm.sha512(password))
window.location.href = "../app/index.html"
}
else if (response.status == 409) {
statusBox.innerText = "Username already taken!"
showElements(true)
}
else {
statusBox.innerText = "Something went wrong!"
showElements(true)
}
}
doStuff()
});
}
doStuff()
});

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M450-450H200v-60h250v-250h60v250h250v60H510v250h-60v-250Z"/></svg>

Before

Width:  |  Height:  |  Size: 163 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>

Before

Width:  |  Height:  |  Size: 209 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>

Before

Width:  |  Height:  |  Size: 300 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="m361-299 119-121 120 121 47-48-119-121 119-121-47-48-120 121-119-121-48 48 120 121-120 121 48 48ZM261-120q-24 0-42-18t-18-42v-570h-41v-60h188v-30h264v30h188v60h-41v570q0 24-18 42t-42 18H261Zm438-630H261v570h438v-570Zm-438 0v570-570Z"/></svg>

Before

Width:  |  Height:  |  Size: 338 B

View File

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 399 B

View File

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 300 B

View File

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 293 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-313 287-506l43-43 120 120v-371h60v371l120-120 43 43-193 193ZM220-160q-24 0-42-18t-18-42v-143h60v143h520v-143h60v143q0 24-18 42t-42 18H220Z"/></svg>

Before

Width:  |  Height:  |  Size: 249 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-240q-17 0-28.5-11.5T240-280v-80h520v-360h80q17 0 28.5 11.5T880-680v600L720-240H280ZM80-280v-560q0-17 11.5-28.5T120-880h520q17 0 28.5 11.5T680-840v360q0 17-11.5 28.5T640-440H240L80-280Zm520-240v-280H160v280h440Zm-440 0v-280 280Z"/></svg>

Before

Width:  |  Height:  |  Size: 338 B

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 244 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

Before

Width:  |  Height:  |  Size: 516 B

View File

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 455 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M180-120q-24 0-42-18t-18-42v-600q0-24 18-42t42-18h299v60H180v600h299v60H180Zm486-185-43-43 102-102H360v-60h363L621-612l43-43 176 176-174 174Z"/></svg>

Before

Width:  |  Height:  |  Size: 247 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M634-320q-14 0-24-10t-10-24v-132q0-14 10-24t24-10h6v-40q0-33 23.5-56.5T720-640q33 0 56.5 23.5T800-560v40h6q14 0 24 10t10 24v132q0 14-10 24t-24 10H634Zm46-200h80v-40q0-17-11.5-28.5T720-600q-17 0-28.5 11.5T680-560v40ZM280-40q-33 0-56.5-23.5T200-120v-720q0-33 23.5-56.5T280-920h400q33 0 56.5 23.5T760-840v160h-80v-40H280v480h400v-40h80v160q0 33-23.5 56.5T680-40H280Zm0-120v40h400v-40H280Zm0-640h400v-40H280v40Zm0 0v-40 40Zm0 640v40-40Z"/></svg>

Before

Width:  |  Height:  |  Size: 538 B

View File

@ -1,82 +0,0 @@
<!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" />
<script type="text/javascript" src="../static/js/crypto-js.js"></script>
</head>
<body>
<div class="topBar">
<p tabindex="0" class="logo" id="burgerButton">Burgernotes</p>
<p tabindex="0" id="usernameBox" class="usernameBox"></p>
</div>
<div class="bottomBar">
<button id="removeBox" class="removeButton"></button>
<button id="wordCountBox">0 words</button>
<div class="textManipulator">
<button id="textMinusBox">-</button>
<button id="textSizeBox">16px</button>
<button id="textPlusBox">+</button>
</div>
</div>
<div id="notesBar" class="notesBar">
<button id="newNote" class="newNote"><img id="newNoteImage" draggable="false" alt=""
src="../static/svg/add.svg">New note</button>
<div id="notesDiv" class="notesDiv">
<button class="loadingStuff" id="loadingStuff"></button>
</div>
</div>
<div id="optionsCoverDiv" class="optionsCoverDiv hidden">
<div id="optionsDiv" class="optionsDiv hidden">
<button class="exit" id="exitThing">X</button>
<h3 class="w300">Your account</h3>
<p id="usernameThing"></p>
<p id="passwordThing"></p>
<div class="section"></div>
<p>Storage</p>
<progress id="storageProgressThing" value="0" max="100"></progress><br>
<p id="storageThing"></p>
<div class="section"></div>
<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>
<div id="errorDiv" class="optionsDiv hidden">
<p id="errorMessageThing"></p>
<input class="hidden" id="errorInput" type="text" placeholder=""><br></input>
<button class="normalButton" id="closeErrorButton">Ok</button>
<button class="normalButton hidden" id="cancelErrorButton">Cancel</button>
</div>
</div>
<textarea id="noteBox" class="noteBox"></textarea>
<script type="text/javascript" src="../static/js/main.js"></script>
<script>
for (let i = 0; i < 40; i++) {
notesDiv.appendChild(loadingStuff.cloneNode())
}
loadingStuff.remove()
</script>
</body>
</html>

View File

@ -1,125 +0,0 @@
<!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">
</head>
<body>
<div class="mainDiv">
<h1>Burgernotes is down</h1>
<p>We're down for maintenance, please try again later!</p>
<!-- please don't mind the spaghetti code :3 -->
<img class="grid" src="/grid.svg">
<img class="grid grid2" src="/grid.svg">
<img class="grid grid3" src="/grid.svg">
<img class="grid grid4" src="/grid.svg">
<img class="grid grid5" src="/grid.svg">
<img class="grid grid6" src="/grid.svg">
<img class="grid grid7" src="/grid.svg">
<img class="grid grid8" src="/grid.svg">
<img class="grid grid9" src="/grid.svg">
<img class="grid grid10" src="/grid.svg">
<img class="grid grid11" src="/grid.svg">
<img class="grid grid12" src="/grid.svg">
<img class="grid grid13" src="/grid.svg">
<img class="grid grid14" src="/grid.svg">
<img class="grid grid15" src="/grid.svg">
<img class="grid grid16" src="/grid.svg">
<img class="grid grid17" src="/grid.svg">
<img class="grid grid18" src="/grid.svg">
<img class="grid grid19" src="/grid.svg">
<img class="grid grid20" src="/grid.svg">
<img class="grid grid21" src="/grid.svg">
<img class="grid grid22" src="/grid.svg">
</div>
</body>
<style>
@import url("/static/fonts/inter.css");
body {
position: absolute;
margin-left: 25px;
left: 0;
bottom: 50%;
font-family: "Inter", sans-serif;
background-color: #202020;
color: white;
}
.grid {
position: fixed;
left: 0;
bottom: 0;
}
.grid2 {
left: 100px;
}
.grid3 {
left: 200px;
}
.grid4 {
left: 300px;
}
.grid5 {
left: 400px;
}
.grid6 {
left: 500px;
}
.grid7 {
left: 600px;
}
.grid8 {
left: 700px;
}
.grid9 {
left: 800px;
}
.grid10 {
left: 900px;
}
.grid11 {
left: 1000px;
}
.grid12 {
left: 1100px;
}
.grid13 {
left: 1200px;
}
.grid14 {
left: 1300px;
}
.grid15 {
left: 1400px;
}
.grid16 {
left: 1500px;
}
.grid17 {
left: 1600px;
}
.grid18 {
left: 1700px;
}
.grid19 {
left: 1800px;
}
.grid20 {
left: 1900px;
}
.grid21 {
left: 2000px;
}
.grid22 {
left: 2100px;
}
</style>
</html>

View File

@ -1,23 +0,0 @@
<!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>

View File

@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Signup - 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">
<script src="../static/js/hash-wasm.js"></script>
<style>
body {
background-color: #d9d9d9;
background-image: url("/static/svg/grid.svg");
background-repeat: repeat;
background-size: 312px
}
.inoutdiv {
border-radius: 8px;
}
</style>
</head>
<body>
<div class="inoutdiv">
<h2 class="w300">Homeserver</h2>
<p>Change your Burgernotes homeserver</p>
<p id="statusBox"></p>
<input type="text" value="https://" id="homeserverBox"><br>
<button id="changeButton">Change</button><br><br>
<p>Please put in the URL in standard format; https://, http://, etc.</p>
</div>
<script type="text/javascript" src="../static/js/homeserver.js"></script>
</body>
</html>

View File

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Login - 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" />
<script src="../static/js/hash-wasm.js"></script>
<style>
body {
background-color: #d9d9d9;
background-image: url("/static/svg/grid.svg");
background-repeat: repeat;
background-size: 312px;
}
.inoutdiv {
border-radius: 8px;
}
</style>
</head>
<body>
<div class="inoutdiv">
<h2 class="w300">Login</h2>
<p id="statusBox"></p>
<span id="inputNameBox" style="margin-right: 10px;color: var(--text-color);"></span>
<input id="usernameBox" class="hidden" type="text" placeholder="Enter your username">
<input id="passwordBox" class="hidden" type="password" placeholder="Enter your password">
<button id="signupButton">Next</button>
<button id="backButton" class="hidden">Back</button>
<br>
<br>
<p>Don't have an account? If so, <a href="../signup/index.html">Create one here!</a></p>
<div style="display: flex;"><p id="homeserver">Your homeserver is loading... </p><div style="display: flex;flex-direction: column;justify-content: center;"><a href="/homeserver">Change</a></div></div>
<a href="../privacy/index.html">Privacy &amp; Terms</a>
</div>
<script type="text/javascript" src="../static/js/login.js"></script>
</body>

View File

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Burgernotes</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<head>
Logging out..
<script>
localStorage.removeItem("DONOTSHARE-secretkey")
localStorage.removeItem("DONOTSHARE-password")
localStorage.removeItem("CACHE-username")
window.location.replace("../index.html")
</script>

View File

@ -1,47 +0,0 @@
<!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" />
<meta content="Burgernotes" property="og:title" />
<meta content="A simple note-taking app!" property="og:description" />
</head>
<body>
<a href="https://notes.old.hectabit.org" class="hiddenButton">Click here</a>
<div class="mainDiv">
<div class="startDiv">
<h1 class="w300">Burgernotes</h1>
<p>A simple note-taking service!</p>
<br>
<a href="./app/index.html">Open in your browser</a>
<a href="./static/burgernotes.mobileconfig" style="margin-top: 5px;">Download for iOS</a>
<a style="padding: 0; padding-bottom: 0; margin-top: 5px; background-color: rgba(0, 0, 0, 0);" href="https://flathub.org/apps/org.hectabit.burgernotes">
<img class="flathubLogo" style="height: 55px;"src="./static/svg/flathublight.svg">
</a>
</div>
<br>
<div class="feature green">
<h7 class="w300">Secure</h7>
<p2>All your notes are fully end-to-end encrypted. Only you can read your notes, not anyone else.</p2>
</div>
<div class="feature yellow">
<h7 class="w300">Always up-to-date</h7>
<p2>Your notes seamlessly sync across your devices.</p2>
</div>
</div>
<div class="links">
<a href="https://centrifuge.hectabit.org/hectabit/burgernotes"><img src="/static/svg/code.svg">Source Code</a>
<a href="../privacy/index.html"><img src="/static/svg/info.svg">Privacy &amp; Terms</a>
<a href="https://discord.gg/8EbKTjmH2d"><img src="/static/svg/forum.svg">Discord</a>
</div>
<br>
</body>
</html>

View File

@ -1,82 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Burgernotes Privacy &amp; Terms</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>
<h1 class="w300">Burgernotes Privacy Policy &amp; Terms & Conditions</h1>
<h2 class="w300">Preamble</h2>
<p><i>Please note that I am not a lawyer, please don't expect too much of this policy :3</i></p>
<p>Welcome to the Burgernotes privacy policy! Burgernotes is <a
href="https://centrifuge.hectabit.org/hectabit/burgernotes">free & open source</a> software licensed under <a
href="https://www.gnu.org/licenses/agpl-3.0.en.html">GNU AGPL-3.0</a>.</p>
<h2 class="w300">Information collected when signing up</h2>
<p>When signing up for an account, we collect and store the following information:</p>
<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>
<ul>
<li>Encrypted note content and title</li>
<li>Note creator</li>
<li>Note creation date</li>
<li>Note last edited date</li>
</ul>
<p>When you edit an note, we collect and use this information:</p>
<ul>
<li>Encrypted note content and title</li>
<li>Note last edited date</li>
</ul>
<h2 class="w300">How we use your data</h2>
<p>We use your data to make our services work. We don't share your information with third-parties.</p>
<h2 class="w300">We can't see notes you create's content and title</h2>
<p>Your notes are <a href="https://en.wikipedia.org/wiki/End-to-end_encryption">encrypted end-to-end</a> using AES
(Advanced Encryption Standard) 256-bit encryption.</p>
<p>We can only see:</p>
<ul>
<li>Note creation date</li>
<li>Note last edited date</li>
<li>Note creator</li>
</ul>
<p>Not note content or title.</p>
<h2 class="w300">We don't sell your data</h2>
<p>We don't sell or share your data to advertisers or third-parties.</p>
<h2 class="w300">Liability</h2>
<p>We take no responsibility for the use of burgernotes, or any external instances provided by third-parties. We
refuse liability for any inappropriate or illegal use of burgernotes.</p>
<p>You may view the AGPL-3.0 license which this software is provided to you with. A copy of the section is below.</p>
<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.</p>
<br>
<button onclick="history.back()" style="cursor: pointer; padding: 15px 20px;margin-right: auto;color: white;text-decoration: none;background-color: var(--theme-color);border-radius: 8px;border: medium;font-size: 15px;">Take me back where I was!</button>
<br><br>
</body>
<style>
body {
margin-left: 15px;
}
</style>
</html>

View File

@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Signup - 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" />
<script src="../static/js/hash-wasm.js"></script>
<style>
body {
background-color: #d9d9d9;
background-image: url("/static/svg/grid.svg");
background-repeat: repeat;
background-size: 312px;
}
.inoutdiv {
border-radius: 8px;
}
</style>
</head>
<body>
<div class="inoutdiv">
<h2 class="w300">Signup</h2>
<p>Signup for a Burgernotes account</p>
<p id="statusBox"></p>
<input id="usernameBox" type="text" placeholder="Username">
<input id="passwordBox" type="password" placeholder="Password"><br>
<button id="signupButton">Signup</button><br><br>
<p>Already have an account? If so, <a href="../login/index.html">Login</a> instead!</p>
<p>Please note that it's impossible to reset your password, do not forget it!</p>
<div style="display: flex;"><p id="homeserver">Your homeserver is loading... </p><div style="display: flex;flex-direction: column;justify-content: center;"><a href="/homeserver">Change</a></div></div>
<a href="../privacy/index.html">Privacy &amp; Terms</a>
</div>
<script type="text/javascript" src="../static/js/signup.js"></script>
</body>