diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45d46e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +server/config +server/history.db diff --git a/frontend/assets/main.css b/frontend/assets/main.css index 5f54ee7..1e69abc 100644 --- a/frontend/assets/main.css +++ b/frontend/assets/main.css @@ -1,3 +1,7 @@ +a:visited { + color: #1b7340; +} + .card { border: 0; box-shadow: 0 .25rem 1rem rgba(48,55,66,.15); diff --git a/frontend/assets/main.js b/frontend/assets/main.js index aa8e8b2..d26c246 100644 --- a/frontend/assets/main.js +++ b/frontend/assets/main.js @@ -1,6 +1,14 @@ +// polyfills for older browsers +if (typeof String.prototype.startsWith === 'undefined') { + String.prototype.startsWith = function (needle) { + return this.indexOf(needle) === 0; + }; +} + // === Core functions === var api_base = "http://localhost:5000"; var app_token = null; +var app_key_id = null; function do_request(method, url, data, onsuccess, onerror) { var req = new XMLHttpRequest(); @@ -26,9 +34,16 @@ function oninit() { window.location.href = "#tracker" app_token = _get_token(); + app_key_id = _get_key_id(app_token); + if (app_token === null || app_key_id === null) { + ui_tracker_error("Interner Fehler: kein/ungültiges Token. Bitte stelle sicher, dass du diese Seite durch Scannen des QR Codes erreicht hast"); + return; + } if (window.location.href.search("#keyholder") > 0) keyholder_onload(); + + update_key_name(); update_key_status(); load_saved_tracker_data(); @@ -43,31 +58,31 @@ function oninit() { } function tracker_onsend(e) { - ui_tracker_noerror(); + ui_tracker_error(false); var name = document.getElementById("input-name").value; var contact = document.getElementById("input-contact").value; var save_data = document.getElementById("input-tracker-save").checked; - if (name.length < 3 || contact.length < 3) { + if (name.length < 2 || contact.length < 2) { ui_tracker_error("Name und Kontakt müssen mindestens 3 Zeichen lang sein") return; } if (app_token === null) { - ui_tracker_error("Interner Fehler: kein Token. Bitte stelle sicher, dass du diese Seite durch Scannen den QR Codes erreicht hast"); + ui_tracker_error("Interner Fehler: kein Token. Bitte stelle sicher, dass du diese Seite durch Scannen des QR Codes erreicht hast"); return; } - document.getElementById("btn-tracker").classList.add("loading"); + ui_tracker_send_loading(true); do_request( "POST", "/claim", "name="+window.encodeURI(name)+"&contact="+window.encodeURI(contact), function(r) { - document.getElementById("btn-tracker").classList.remove("loading"); + ui_tracker_send_loading(true); if (r.status == 200) { - localStorage.setItem("last_cid", r.response); + localStorage.setItem(app_key_id + "_last_cid", r.response); if (save_data) { localStorage.setItem("name", name); localStorage.setItem("contact", contact); @@ -83,7 +98,7 @@ function tracker_onsend(e) { } }, function(r) { - document.getElementById("btn-tracker").classList.remove("loading"); + ui_tracker_send_loading(true); ui_tracker_error("Fehlgeschlagen: Bitte überprüfe deine Internetverbindung"); console.log("Claim request failed"); console.log(r); @@ -92,14 +107,16 @@ function tracker_onsend(e) { } function keyholder_onload() { - ui_password_noerror(); - ui_keyholder_noerror(); + ui_password_error(false); + ui_keyholder_error(false); + ui_keyholder_refresh_loading(true); do_request( "GET", "/keyholder", null, function(r) { + ui_keyholder_refresh_loading(false); if (r.status == 200) { ui_show_keyholder(JSON.parse(r.response)); } else if (r.status == 403) { @@ -111,6 +128,7 @@ function keyholder_onload() { } }, function(r) { + ui_keyholder_refresh_loading(false); ui_keyholder_error("Fehlgeschlagen: Bitte überprüfe deine Internetverbindung"); console.log("Keyholder request failed"); console.log(r); @@ -119,8 +137,8 @@ function keyholder_onload() { } function password_submit() { - ui_password_noerror(); - ui_keyholder_noerror(); + ui_password_error(false); + ui_keyholder_error(false); var pass = document.getElementById("input-pass").value; var save_token = document.getElementById("input-pass-save").checked; @@ -133,17 +151,28 @@ function password_submit() { function(r) { document.getElementById("btn-send-pw").classList.remove("loading"); if (r.status == 200) { + // Delete previously used token + if (app_token !== null && localStorage.getItem("token") !== null) { + var tokenlist = localStorage.getItem("token").split(","); + if (tokenlist.indexOf(app_token) !== -1) { + tokenlist.splice(tokenlist.indexOf(app_token), 1); + localStorage.setItem("token", tokenlist.join(",")); + } + } + app_token = r.response; - if (save_token) - localStorage.setItem("token", app_token); - else - localStorage.removeItem("token"); + if (save_token) { + if (localStorage.getItem("token") !== null) + localStorage.setItem("token", localStorage.getItem("token") + "," + app_token); + else + localStorage.setItem("token", app_token) + } ui_keyholder_loading(); keyholder_onload(); } else if (r.status == 401) { - ui_password_error(); + ui_password_error(true); } else { ui_keyholder_error("Fehlgeschlagen: Status code " + r.status); console.log("Auth request failed (Status code)"); @@ -162,10 +191,11 @@ function password_submit() { // === Helper functions === function update_key_status() { - if (localStorage.getItem("last_cid") !== null) { + var last_cid = localStorage.getItem(app_key_id + "_last_cid"); + if (last_cid !== null) { do_request( "GET", - "/status/" + localStorage.getItem("last_cid"), + "/status/" + last_cid, null, function(r) { if (r.status == 200 && r.response == "latest") @@ -178,6 +208,32 @@ function update_key_status() { } } +function update_key_name() { + // For perception purposes, the last key name is cached but + // updated as soon as possible. + var last_key_name = localStorage.getItem(app_key_id + "_last_key_name"); + if (last_key_name !== null) + ui_set_key_name(last_key_name); + do_request( + "GET", + "/keyname", + null, + function(r) { + if (r.status == 200) { + ui_set_key_name(r.response); + localStorage.setItem(app_key_id + "_last_key_name", r.response); + } else { + ui_set_key_name("?"); + console.log("Keyname request failed (status code " + r.status + ")"); + } + }, + function(r) { + ui_set_key_name("?"); + console.log("Keyname request failed"); console.log(r) + } + ); +} + function load_saved_tracker_data() { if (localStorage.getItem("name") !== null) document.getElementById("input-name").value = localStorage.getItem("name"); @@ -186,19 +242,44 @@ function load_saved_tracker_data() { } function _get_token() { - if (localStorage.getItem("token") === null) { - // Very dirty parsing as of now - var params_str = window.location.search; - if (params_str.search("&") >= 0) - return null; + // A token in the URL is always required to know the key + var token = null; + // Very dirty parsing as of now + var params_str = window.location.search; + if (params_str.search("&") >= 0) + return null; - var parts = params_str.split("token="); - if (parts.length != 2) + var parts = params_str.split("token="); + if (parts.length != 2) + return null + else + token = parts[1]; + + if (localStorage.getItem("token") === null) { + return token; + } else { + var key_id = token.split(":")[0]; + + var tokenlist = localStorage.getItem("token").split(","); + // This returns the last stored token for this key. + // Generally it should not happen (tm) that there is more than one token. + for (var i = tokenlist.length - 1; i >= 0; i--) { + if (tokenlist[i].indexOf(key_id + ":") === 0) + return tokenlist[i]; + } + return token; + } +} + +function _get_key_id(token) { + if (token === null) { + return null; + } else { + var parts = token.split(":"); + if (parts.length !== 2) return null else - return parts[1]; - } else { - return localStorage.getItem("token"); + return parts[0]; } } @@ -222,6 +303,11 @@ function ui_set_has_not_key() { document.getElementById("tracker-formgroup").style.opacity = 1 } +function ui_set_key_name(name) { + document.getElementById("tracker-key-name").textContent = name; + document.getElementById("keyholder-key-name").textContent = name; +} + function ui_keyholder_loading() { document.getElementById("keyholder-loading").style.display = "block" document.getElementById("btn-send-pw").style.display = "none" @@ -265,28 +351,41 @@ function ui_show_keyholder(keyholder) { document.getElementById("keyholder-table-container").style.display = "block" } -function ui_tracker_error(msg) { - document.getElementById("tracker-error").innerHTML = msg; - document.getElementById("tracker-error").style.display = "block"; +function ui_keyholder_refresh_loading(is_loading) { + if (is_loading) + document.getElementById("btn-update").classList.add("loading"); + else + document.getElementById("btn-update").classList.remove("loading"); } -function ui_tracker_noerror(msg) { - document.getElementById("tracker-error").style.display = "none"; +function ui_tracker_send_loading(is_loading) { + if (is_loading) + document.getElementById("btn-tracker").classList.add("loading"); + else + document.getElementById("btn-tracker").classList.remove("loading"); +} + +function ui_tracker_error(msg) { + if (msg === false) { + document.getElementById("tracker-error").style.display = "none"; + } else { + document.getElementById("tracker-error").innerHTML = msg; + document.getElementById("tracker-error").style.display = "block"; + } } function ui_keyholder_error(msg) { - document.getElementById("keyholder-error").innerHTML = msg; - document.getElementById("keyholder-error").style.display = "block"; + if (msg === false) { + document.getElementById("keyholder-error").style.display = "none"; + } else { + document.getElementById("keyholder-error").innerHTML = msg; + document.getElementById("keyholder-error").style.display = "block"; + } } -function ui_keyholder_noerror(msg) { - document.getElementById("keyholder-error").style.display = "none"; -} - -function ui_password_error() { - document.getElementById("input-pass").classList.add("is-error") -} - -function ui_password_noerror() { - document.getElementById("input-pass").classList.remove("is-error") +function ui_password_error(is_error) { + if (is_error) + document.getElementById("input-pass").classList.add("is-error"); + else + document.getElementById("input-pass").classList.remove("is-error"); } diff --git a/frontend/index.html b/frontend/index.html index 5c61b4f..d609151 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -17,6 +17,7 @@
Schlüsseltracker
+
für: ...
@@ -54,7 +55,10 @@