diff --git a/pass/lang/en/key.json b/pass/lang/en/key.json index a5c9eae7d1ea4b803e836318e45a515b2633ffdc..d46531748fb0245b00c4503315fb6b4677152ece 100644 --- a/pass/lang/en/key.json +++ b/pass/lang/en/key.json @@ -19,14 +19,9 @@ "fill": "Charge", "orders": "Orders", "valid_until": "valid until", - "new": { - "heading": "This is how it continues", - "text": "Your MetaGer key has been created and set up. It just needs to be charged. Please make sure beforehand that you have saved the key so that you can enter it if the setting in your browser is deleted. For this you need either the key itself, above URL or the QR code as a file.", - "charge": "Charge key now" - }, "startpagelinks": { "adfree": "To the ad-free search", "regular": "To MetaGer search" } } -} +} \ No newline at end of file diff --git a/pass/lang/en/login.json b/pass/lang/en/login.json index 663357d19f3a86125eec87103150a508e7b354b8..92d77ef94aef50332fbb1a23c997b5bddcf1d9d9 100644 --- a/pass/lang/en/login.json +++ b/pass/lang/en/login.json @@ -13,5 +13,22 @@ }, "submit": "Submit", "create": "Set up ad-free search", - "error": "A valid key, or a valid backup file is required." -} + "error": "A valid key, or a valid backup file is required.", + "generate": { + "heading": "Ihr neuer MetaGer Schlüssel", + "first_step": "MetaGer Schlüssel erstellen", + "copy-key": "Schlüssel kopieren", + "initialize": { + "description": "Erstellen Sie sich ganz einfach auf Knopfdruck einen neuen Schlüssel für werbefreie Suchen", + "button": "Schlüssel jetzt erstellen" + }, + "processing": { + "description": "Einen Moment: Wir erstellen Ihnen gerade einen neuen, zufälligen MetaGer Schlüssel..." + }, + "store": { + "description": "Ihr neuer Schlüssel wurde erstellt und in diesem Browser hinterlegt. Bitte speichern Sie ihn dennoch ab! Er wird Ihre Token enthalten, die für die werbefreie Suche verwendet werden. Sie müssen den Schlüssel nur eingeben, wenn Sie ihn auf weiteren Geräten verwenden möchten, oder wenn die Cookies in Ihrem Browser gelöscht wurden.", + "url": "Sie können auch diese URL z.B. als Lesezeichen abspeichern, um den Schlüssel ohne manuelle Eingabe im Browser wiederherzustellen." + }, + "next": "Weiter zum nächsten Schritt: " + } +} \ No newline at end of file diff --git a/pass/public/js/create.js b/pass/public/js/create.js new file mode 100644 index 0000000000000000000000000000000000000000..0b08fa6f7fc486d979bcec9e83937c62222f10d6 --- /dev/null +++ b/pass/public/js/create.js @@ -0,0 +1,49 @@ +let container = document.getElementById("create"); +let keyContainer = document.getElementById("key"); +let initializeButton = document.querySelector("div.initialize > button"); +let key = keyContainer.dataset.key; + +let characters = ["a", "b", "c", "d", "e", "f", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; + +container.dataset.state = "initialize"; +keyContainer.parentNode.querySelector("button.button").classList.add("disabled"); + +let runtime = 5000; // Runtime in milliseconds +let starttime = Date.now(); + +initializeButton.addEventListener("click", () => { + starttime = Date.now(); + container.dataset.state = "processing"; + generateRandomKey(0); + let interval = setInterval(() => { + if ((starttime + runtime) < Date.now()) { + clearInterval(interval); + container.dataset.state = "finished"; + keyContainer.parentNode.querySelector("button.button").classList.remove("disabled"); + } + let steps = runtime / 32; + let skipped_characters = Math.ceil((Date.now() - starttime) / steps); + generateRandomKey(skipped_characters); + }, 100); +}); + +function generateRandomKey(skip) { + let random_key = ""; + if (!skip) { + skip = 0; + } else { + skip = Math.max(Math.min(32, skip), 0); + } + for (let i = 0; i < 32; i++) { + let character = ""; + if (i == 8 || i == 12 || i == 16 || i == 20) { + random_key += "-"; + } + character = characters[Math.floor(Math.random() * characters.length)]; + if (skip > i) { + character = key.replaceAll("-", "").charAt(i); + } + random_key += character; + } + keyContainer.value = random_key; +} \ No newline at end of file diff --git a/pass/public/styles/key/create.less b/pass/public/styles/key/create.less new file mode 100644 index 0000000000000000000000000000000000000000..fff98bd86e3af71620b45ab535ad2f6de2aa33f3 --- /dev/null +++ b/pass/public/styles/key/create.less @@ -0,0 +1,115 @@ +@import "../misc/vars.less"; +#create { + display: grid; + gap: 2rem; + h1, + h2 { + margin: 0; + line-height: 1; + } + > h2 { + border-bottom: 1px solid @color-main; + } + > div.initialize { + display: grid; + gap: 1rem; + > button { + margin: 0 auto; + padding-block: 0.5rem; + } + } + div.copy-group { + > button { + padding-block: 0.5rem; + &.disabled { + color: lighten(#777, 50%); + } + } + > input { + min-width: 50ch; + padding-inline: 1rem; + } + &.key { + display: grid; + grid-template-columns: max-content max-content; + place-content: center; + > label { + grid-column: span 2; + color: lighten(@font-color-on-white, 20%); + font-size: 0.8rem; + } + + @media (max-width: 580px) { + grid-template-columns: 1fr; + > label { + grid-column: initial; + } + > input { + padding-block: 0.5rem; + min-width: initial; + } + > button { + width: 100%; + } + } + > input { + letter-spacing: 0.2ch; + text-align: center; + } + } + } + > div#processing-description { + text-align: center; + } + > div#store { + display: grid; + gap: 1rem; + + > div.copy-group { + display: grid; + grid-template-columns: 1fr max-content; + place-content: center; + @media (max-width: 580px) { + grid-template-columns: 1fr; + > button { + width: 100%; + } + > input { + padding-block: 0.5rem; + min-width: initial; + } + } + } + } + > hr { + width: 100%; + } + > a.button { + margin: 0 auto; + font-size: clamp(12px, 4vw, 16px); + } + + &[data-state="initialize"] { + > div.key, + > div#processing-description, + > div#store, + > hr, + > a.button { + display: none; + } + } + &[data-state="finished"] { + > div.initialize, + > div#processing-description { + display: none; + } + } + &[data-state="processing"] { + > div.initialize, + > div#store, + > hr, + > a.button { + display: none; + } + } +} diff --git a/pass/routes/key.js b/pass/routes/key.js index 07f72d23f1e1596214a00f3d201c969e5e8f70c2..9aba57ba0e6ad64d5765f6613c7ecb003a3a72c0 100644 --- a/pass/routes/key.js +++ b/pass/routes/key.js @@ -17,9 +17,28 @@ router.get("/create", function (req, res, next) { return res.redirect(`${res.locals.baseDir}/key/enter`); } Key.GET_NEW_KEY().then((key) => { - res.redirect( - `${res.locals.baseDir}/key/` + key.get_key() + "?new=true#second-nav" - ); + res.locals.key = key; + + let setting_url = res.baseDir.replace(/\/keys.*/, ""); + setting_url += "/meta/settings/load-settings?"; + + let params = { + key: key.get_key(), + }; + + for (let cookie in req.cookies) { + if ( + cookie.match( + /^(dark_mode$|new_tab$|zitate$|web_|bilder_|produkte_|nachrichten_|science_)/ + ) + ) { + params[cookie] = req.cookies[cookie]; + } + } + setting_url += new URLSearchParams(params).toString(); + res.locals.setting_url = setting_url; + + res.render("login/create"); }); }); @@ -145,7 +164,6 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => { Key.GET_KEY(req.params.key, false).then((key) => { req.data = { - created_new: req.query.new === "true" ? true : false, price: config.get("price"), key: { key: key, diff --git a/pass/views/key.ejs b/pass/views/key.ejs index 16b52e2a730182cc9ccb89d725d0c0a300440443..eedb00658608fe64b1d3ac32c915cbf5a444d9dc 100644 --- a/pass/views/key.ejs +++ b/pass/views/key.ejs @@ -40,13 +40,7 @@ <a class="button <% if(page === "fill") { _%> active<%_ } _%>" href="<%= links.fill_url %>"><%= req.t("key.fill", {ns: "key"}) _%></a> <a class="button <% if(page === "order") { _%> active<%_ } %>" href="<%= links.orders_url %>"><%= req.t("key.orders", {ns: "key"}) _%></a> </nav> -<%_ if (created_new) { _%> -<div id="store"> - <h2><%= req.t("key.new.heading", {ns: "key"}) %>:</h2> - <p><%= req.t("key.new.text", {ns: "key"}) %></p> - <a class="button" href="<%= baseDir _%>/key/<%= key.key.get_key() %>#second-nav"><%= req.t("key.new.charge", {ns: "key"}) %></a> -</div> -<% } else if (page === "order") { %> +<% if (page === "order") { %> <%_ if(typeof order === "undefined") { _%> <%- include('./orders/orders', {}); %> <%_ } else { _%> diff --git a/pass/views/login/create.ejs b/pass/views/login/create.ejs new file mode 100644 index 0000000000000000000000000000000000000000..e80d6165349095e53890ee01e12886dfed5976b2 --- /dev/null +++ b/pass/views/login/create.ejs @@ -0,0 +1,29 @@ +<%- include('../templates/page_header', {css: +[`${baseDir}/styles/key/create.css`], js:[`${baseDir}/js/create.js`]}); %> + +<div id="create" data-state="finished"> + <h1><%= req.t("generate.heading", {ns: "login"}) _%></h1> + <h2>1. <%= req.t("generate.first_step", {ns: "login"}) _%></h2> + <div class="initialize"> + <div><%= req.t("generate.initialize.description", {ns: "login"}) _%></div> + <button class="button"><%= req.t("generate.initialize.button", {ns: "login"}) _%></button> + </div> + <div class="copy-group key"> + <label for="key"><%= req.t("title", {ns: "pageheader"}) _%></label> + <input type="text" name="key" id="key" value="<%= key.get_key() _%>" data-key="<%= key.get_key() _%>" readonly> + <button class="copy button" data-target="key"><%= req.t("generate.copy-key", {ns: "login"}) _%></button> + </div> + <div id="processing-description"><%= req.t("generate.processing.description", {ns: "login"}) _%></div> + <div id="store"> + + <div><%= req.t("generate.store.description", {ns: "login"}) _%></div> + <div><%= req.t("generate.store.url", {ns: "login"}) _%></div> + <div class="copy-group setting-url"> + <input type="text" name="setting-url" id="setting-url" value="<%= setting_url _%>"> + <button class="copy button" data-target="setting-url"><%= req.t("key.copy-url", {ns: "key"}) _%></button> + </div> + </div> + <hr> + <a class="button" href="<%= baseDir _%>/key/<%= key.get_key() _%>#charge"><%= req.t("generate.next", {ns: "login"}) _%> <%= req.t("howitworks.steps.1.heading", {ns: "index"}) _%></a> + + <%- include('../templates/page_footer'); -%> \ No newline at end of file diff --git a/pass/views/login/key.ejs b/pass/views/login/key.ejs index 51787fa573bcf753f62580e096bb949612c7fe27..7441d54921bf564fbb92371ec6ccc8297400d168 100644 --- a/pass/views/login/key.ejs +++ b/pass/views/login/key.ejs @@ -8,12 +8,7 @@ <%= req.t("heading", {ns: "login"}) _%> <a href="<%= baseDir %>" class="hint-icon">?</a> </h3> - <form - id="key-form" - action="<%= baseDir _%>/key/enter" - method="post" - enctype="multipart/form-data" - > + <form id="key-form" action="<%= baseDir _%>/key/enter" method="post" enctype="multipart/form-data"> <input type="text" name="key" id="key" placeholder="<%= req.t("key-input.placeholder", {ns: "login"}) _%>" /> </form> @@ -57,9 +52,7 @@ </div> </div> <div id="create"> - <a href="<%= baseDir _%>/key/create#second-nav" class="button" - ><%= req.t("create", {ns: "login"}) _%></a - > + <a href="<%= baseDir _%>/key/create#create" class="button"><%= req.t("create", {ns: "login"}) _%></a> </div> -<%- include('../templates/page_footer'); -%> +<%- include('../templates/page_footer'); -%> \ No newline at end of file diff --git a/pass/views/templates/page_header.ejs b/pass/views/templates/page_header.ejs index 6b5ddfb8918bec41a42a37726144c15785faa6a8..d0f036c748422810789eda27414f411932018079 100644 --- a/pass/views/templates/page_header.ejs +++ b/pass/views/templates/page_header.ejs @@ -92,7 +92,7 @@ <li><a href="<%= baseDir _%>/key/remove" class="" id="key-remove"><%= req.t("rightnav.logout", { ns: 'pageheader'}) _%></a></li> <%_ } else { _%> <li><a href="<%= baseDir _%>/key/enter"><%= req.t("rightnav.enter", { ns: 'pageheader'}) _%></a></li> - <li><a href="<%= baseDir _%>/key/create" class="button"><%= req.t("rightnav.start", { ns: 'pageheader'}) _%></a></li> + <li><a href="<%= baseDir _%>/key/create#create" class="button"><%= req.t("rightnav.start", { ns: 'pageheader'}) _%></a></li> <%_ } _%> </ul>