Browse Source

feat(install): faux install validation using npm sha512 digest

updates #33
Josh Habdas 11 months ago
parent
commit
5a8dec0424
Signed by: Josh Habdas <jhabdas@protonmail.com> GPG Key ID: B148B31154C75A74

+ 18
- 66
archetypes/help.md View File

@@ -1,88 +1,40 @@
1 1
 +++
2
-title = "{{ replace .TranslationBaseName "-" " " | title }}"
3
-date = {{ .Date }}
2
+title = "Help {{ .Site.Data.theme.latest.version }}"
3
+date = {{ .Date }} # TODO: Remove?
4 4
 expirydate = {{ .Date }}
5
-description = "Thank you for choosing After Dark. Please customize your installation."
6 5
 noindex = true
7 6
 toc = true
7
+type = "help"
8
+layout = "help"
9
+[installation]
10
+  sha512 = "{{ strings.TrimLeft "sha512-" .Site.Data.theme.latest.dist.integrity }}"
8 11
 +++
9 12
 
10
-{{< hackcss-form name="validate" action="/post/welcome/" >}}
13
+{{< hackcss-form name="validate" action="/help/" >}}
11 14
   {{< hackcss-formgroup name="validation" >}}
12
-    {{< hackcss-label for="pgp" >}}
13
-      64-bit <abbr title="Pretty Good Privacy">PGP</abbr> key:
15
+    {{< hackcss-label for="sha512" >}}
16
+      <abbr title="Secure Hash Algorithm">SHA-512</abbr> Digest:
14 17
     {{< /hackcss-label >}}
15 18
     {{< hackcss-textinput
16 19
         required="true"
17 20
         autofocus="true"
18 21
         autocomplete="off"
19
-        value="BB73 67EE 9A70 A631"
20
-        type="text" id="pgp" name="pgp"
21
-        pattern="^(?:[A-Za-z0-9+/]{4}\s){3}(?:[A-Za-z0-9+/]{4})$" >}}
22
+        type="text" id="sha512" name="sha512"
23
+        pattern="^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" >}}
22 24
     {{< hackcss-helpblock >}}
23
-      Submit with key to verify installation.
25
+      Submit with digest to validate installation.
24 26
     {{< /hackcss-helpblock >}}
25 27
   {{< /hackcss-formgroup >}}
26 28
 {{< /hackcss-form >}}
27 29
 
28
-<script>
29
-  (function (window, document, undefined) {
30
-    "use strict";
31
-    const key = 'BB73 67EE 9A70 A631';
32
-    const confirm = fragment => {
33
-      document.body.insertBefore(fragment, document.body.firstChild);
34
-      const form = document.forms.validate;
35
-      form.pgp.value = key;
36
-      form.validation.classList.add('form-success');
37
-      form.validation.disabled = true;
38
-      const message = "Key verified. Valid installation detected."
39
-      form.querySelector('.help-block').innerHTML = message;
40
-    };
41
-    const validate = (search, form) => {
42
-      search.includes(key.replace(/\s/g,'+')) ? confirm(form) : challenge(form);
43
-    };
44
-    const challenge = fragment => {
45
-      const body = document.body;
46
-      if (body.firstChild === document.forms.validate) return;
47
-      while (body.firstChild) body.removeChild(body.firstChild);
48
-      body.insertBefore(fragment, body.firstChild);
49
-      const form = document.forms.validate;
50
-      const check = () => {
51
-        const classes = form.validation.classList;
52
-        if (form.checkValidity()) {
53
-          classes.add('form-success');
54
-          classes.remove('form-warning');
55
-        } else {
56
-          classes.add('form-warning');
57
-          classes.remove('form-success');
58
-        }
59
-      };
60
-      form.oninput = check;
61
-      document.location.pathname !== '/' && (() => {
62
-        form.validation.classList.add('form-error');
63
-        document.title = "Please try again…";
64
-        const help = form.querySelector('.help-block');
65
-        help.innerHTML = help.innerHTML.replace(
66
-          'key', `<mark><b>${key}</b></mark>`
67
-        );
68
-        help.innerHTML = help.innerHTML.replace(' installation', '');
69
-      })();
70
-    };
71
-    const initialize = () => {
72
-      const fragment = document.createDocumentFragment();
73
-      fragment.appendChild(document.forms.validate);
74
-      (document.location.search.replace('?pgp=','').length)
75
-        ? validate(location.search, fragment)
76
-        : challenge(fragment);
77
-    };
78
-    document.onreadystatechange = () => {
79
-      document.readyState === 'interactive' && initialize();
80
-    };
81
-  })(window, document);
82
-</script>
83
-
84 30
 <!--more-->
85 31
 
32
+Welcome to the Online Help for After Dark. Here you will find instructions for configuring your site. Use the [Table of Contents](#TableOfContents) to quickly jump to any section.
33
+
34
+If you're unable to find what you're looking for, or just need a helping hand, please join the private telegram chatroom and ask for help. Active chatroom link can be found at the top of the `README` in the latest version of the theme.
35
+
36
+To return to this documentation at anytime use `hugo serve --buildExpired`.
37
+
86 38
 # Module System
87 39
 
88 40
 After Dark includes a custom module system and provides a number of prebuilt modules. Modules use Hugo [Theme Components](https://gohugo.io/themes/theme-components/) and are packaged using NPM for convenience. A summary of available modules can be found in the following table.

+ 5
- 0
bin/help View File

@@ -0,0 +1,5 @@
1
+#!/bin/sh
2
+echo "Starting help server ..."
3
+hugo serve --buildExpired --disableLiveReload --port 1414 1>/dev/null &
4
+echo "Help server started at http://localhost:1414/"
5
+echo "To stop it run \"kill \$(ps aux | awk '/[h]ugo.*1414/ {print \$2}')\"."

+ 5
- 3
bin/install View File

@@ -32,8 +32,8 @@ create_site () {
32 32
 
33 33
 download_theme () {
34 34
    echo "Downloading the latest version of After Dark ..."
35
-   meta=$(wget -qO - https://registry.npmjs.org/after-dark/latest)
36
-   vers=$(echo "$meta" | egrep -o "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
35
+   THEME_META=$(wget -qO - https://registry.npmjs.org/after-dark/latest)
36
+   vers=$(echo "$THEME_META" | egrep -o "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
37 37
    mkdir -p themes/after-dark
38 38
    wget -qO - https://registry.npmjs.org/after-dark/-/after-dark-"$vers".tgz | tar --strip-components=1 -xz -C themes/after-dark
39 39
    echo "Version $vers downloaded to $SITE_DIR/themes/after-dark"
@@ -51,6 +51,7 @@ download_module () {
51 51
 
52 52
 configure_theme () {
53 53
    echo "Configuring basic After Dark theme settings ..."
54
+   mkdir data/theme && echo -E "$THEME_META" > data/theme/latest.json
54 55
    tee "config.toml" > /dev/null <<TOML
55 56
 baseurl = "https://domain.example/" # Controls base URL sitewide
56 57
 languageCode = "en-US" # Controls site language
@@ -96,7 +97,8 @@ update_archetypes () {
96 97
 
97 98
 generate_help_docs () {
98 99
    echo "Generating help documentation ..."
99
-   hugo new post/welcome.md --kind help 1>/dev/null
100
+   mkdir data/theme && echo "$THEME_META" | tr '\r\n' ' ' > data/theme/latest.json
101
+   hugo new help/index.md --kind help 1>/dev/null
100 102
 }
101 103
 
102 104
 serve_help_docs () {

+ 1
- 0
layouts/_default/baseof.html View File

@@ -43,6 +43,7 @@
43 43
         <link href={{ "/css/syntax.css" | relURL }} rel="stylesheet">
44 44
       </noscript>
45 45
     {{ end }}
46
+    {{ partial "head/validate-maybe.html" . }}
46 47
   </head>
47 48
   {{ $hackcss_disabled := .Site.Params.hackcss.disabled | default false }}
48 49
   {{ $hackcss_mode := .Site.Params.hackcss.mode | default "hack" }}

+ 13
- 0
layouts/_default/help.html View File

@@ -0,0 +1,13 @@
1
+{{ define "title" -}}
2
+  {{ .Title }} | {{ .Site.Title }}
3
+{{- end }}
4
+{{ define "header" }}
5
+  {{ partial "menu.html" . }}
6
+{{ end }}
7
+{{ define "main" }}
8
+  {{ partial "toc-maybe.html" . }}
9
+  {{ .Content }}
10
+{{ end }}
11
+{{ define "footer" }}
12
+  {{ partial "powered-by.html" . }}
13
+{{ end }}

+ 1
- 1
layouts/index.html View File

@@ -8,7 +8,7 @@
8 8
   <header>
9 9
     <h1>{{ .Title }}</h1>
10 10
   </header>
11
-  {{ range (.Paginate (where .Data.Pages "Type" "post")).Pages }}
11
+  {{ range (.Paginate (where .Data.Pages "Type" "in" (slice "post" "help"))).Pages }}
12 12
     {{ partial "page-summary.html" . }}
13 13
   {{ end }}
14 14
 {{ end }}

+ 65
- 0
layouts/partials/head/validate-maybe.html View File

@@ -0,0 +1,65 @@
1
+{{ $scratch := newScratch }}
2
+{{ range where .Site.RegularPages "Type" "help" }}
3
+  {{ $scratch.Set "sha512" .Params.installation.sha512 }}
4
+{{ end }}
5
+{{ if $scratch.Get "sha512" }}
6
+  <script>
7
+    (function (window, document, undefined) {
8
+      "use strict";
9
+      const sha512 = '{{ $scratch.Get "sha512" }}';
10
+      const confirm = fragment => {
11
+        document.body.insertBefore(fragment, document.body.firstChild);
12
+        const form = document.forms.validate;
13
+        form.sha512.type = 'password';
14
+        form.sha512.value = sha512;
15
+        form.validation.classList.add('form-success');
16
+        form.validation.disabled = true;
17
+        const message = "Signature verified. Valid installation detected."
18
+        form.querySelector('.help-block').innerHTML = message;
19
+      };
20
+      const validate = (search, form) => {
21
+        search.includes(encodeURIComponent(sha512)) ? confirm(form) : challenge(form);
22
+      };
23
+      const challenge = fragment => {
24
+        const body = document.body;
25
+        if (body.firstChild === document.forms.validate) return;
26
+        while (body.firstChild) body.removeChild(body.firstChild);
27
+        body.insertBefore(fragment, body.firstChild);
28
+        const form = document.forms.validate;
29
+        form.sha512.value = sha512;
30
+        const check = () => {
31
+          const classes = form.validation.classList;
32
+          if (form.checkValidity()) {
33
+            classes.add('form-success');
34
+            classes.remove('form-warning');
35
+          } else {
36
+            classes.add('form-warning');
37
+            classes.remove('form-success');
38
+          }
39
+        };
40
+        form.oninput = check;
41
+        document.location.pathname !== '/' && (() => {
42
+          form.validation.classList.add('form-error');
43
+          document.title = "Invalid | {{ .Site.Title }}";
44
+          const help = form.querySelector('.help-block');
45
+          help.innerHTML = help.innerText = "Signature invalid. Please try again.";
46
+          const alert = document.createElement('div');
47
+          alert.classList.add('alert');
48
+          alert.classList.add('alert-warning');
49
+          alert.innerHTML = '<strong>WARNING</strong> Bad digest detected. Installation may be corrupt.';
50
+          document.body.appendChild(alert);
51
+        })();
52
+      };
53
+      const initialize = () => {
54
+        const fragment = document.createDocumentFragment();
55
+        fragment.appendChild(document.forms.validate);
56
+        (document.location.search.replace('?sha512=','').length)
57
+          ? validate(location.search, fragment)
58
+          : challenge(fragment);
59
+      };
60
+      document.onreadystatechange = () => {
61
+        document.readyState === 'interactive' && initialize();
62
+      };
63
+    })(window, document);
64
+  </script>
65
+{{ end }}

Loading…
Cancel
Save