Browse Source

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

updates #33
pull/73/head
Josh Habdas 2 years ago
parent
commit
5a8dec0424
Signed by: jhabdas GPG Key ID: B148B31154C75A74
7 changed files with 108 additions and 70 deletions
  1. +18
    -66
      archetypes/help.md
  2. +5
    -0
      bin/help
  3. +5
    -3
      bin/install
  4. +1
    -0
      layouts/_default/baseof.html
  5. +13
    -0
      layouts/_default/help.html
  6. +1
    -1
      layouts/index.html
  7. +65
    -0
      layouts/partials/head/validate-maybe.html

+ 18
- 66
archetypes/help.md View File

@ -1,88 +1,40 @@
+++
title = "{{ replace .TranslationBaseName "-" " " | title }}"
date = {{ .Date }}
title = "Help {{ .Site.Data.theme.latest.version }}"
date = {{ .Date }} # TODO: Remove?
expirydate = {{ .Date }}
description = "Thank you for choosing After Dark. Please customize your installation."
noindex = true
toc = true
type = "help"
layout = "help"
[installation]
sha512 = "{{ strings.TrimLeft "sha512-" .Site.Data.theme.latest.dist.integrity }}"
+++
{{< hackcss-form name="validate" action="/post/welcome/" >}}
{{< hackcss-form name="validate" action="/help/" >}}
{{< hackcss-formgroup name="validation" >}}
{{< hackcss-label for="pgp" >}}
64-bit <abbr title="Pretty Good Privacy">PGP</abbr> key:
{{< hackcss-label for="sha512" >}}
<abbr title="Secure Hash Algorithm">SHA-512</abbr> Digest:
{{< /hackcss-label >}}
{{< hackcss-textinput
required="true"
autofocus="true"
autocomplete="off"
value="BB73 67EE 9A70 A631"
type="text" id="pgp" name="pgp"
pattern="^(?:[A-Za-z0-9+/]{4}\s){3}(?:[A-Za-z0-9+/]{4})$" >}}
type="text" id="sha512" name="sha512"
pattern="^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" >}}
{{< hackcss-helpblock >}}
Submit with key to verify installation.
Submit with digest to validate installation.
{{< /hackcss-helpblock >}}
{{< /hackcss-formgroup >}}
{{< /hackcss-form >}}
<script>
(function (window, document, undefined) {
"use strict";
const key = 'BB73 67EE 9A70 A631';
const confirm = fragment => {
document.body.insertBefore(fragment, document.body.firstChild);
const form = document.forms.validate;
form.pgp.value = key;
form.validation.classList.add('form-success');
form.validation.disabled = true;
const message = "Key verified. Valid installation detected."
form.querySelector('.help-block').innerHTML = message;
};
const validate = (search, form) => {
search.includes(key.replace(/\s/g,'+')) ? confirm(form) : challenge(form);
};
const challenge = fragment => {
const body = document.body;
if (body.firstChild === document.forms.validate) return;
while (body.firstChild) body.removeChild(body.firstChild);
body.insertBefore(fragment, body.firstChild);
const form = document.forms.validate;
const check = () => {
const classes = form.validation.classList;
if (form.checkValidity()) {
classes.add('form-success');
classes.remove('form-warning');
} else {
classes.add('form-warning');
classes.remove('form-success');
}
};
form.oninput = check;
document.location.pathname !== '/' && (() => {
form.validation.classList.add('form-error');
document.title = "Please try again…";
const help = form.querySelector('.help-block');
help.innerHTML = help.innerHTML.replace(
'key', `<mark><b>${key}</b></mark>`
);
help.innerHTML = help.innerHTML.replace(' installation', '');
})();
};
const initialize = () => {
const fragment = document.createDocumentFragment();
fragment.appendChild(document.forms.validate);
(document.location.search.replace('?pgp=','').length)
? validate(location.search, fragment)
: challenge(fragment);
};
document.onreadystatechange = () => {
document.readyState === 'interactive' && initialize();
};
})(window, document);
</script>
<!--more-->
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.
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.
To return to this documentation at anytime use `hugo serve --buildExpired`.
# Module System
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 @@
#!/bin/sh
echo "Starting help server ..."
hugo serve --buildExpired --disableLiveReload --port 1414 1>/dev/null &
echo "Help server started at http://localhost:1414/"
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 () {
download_theme () {
echo "Downloading the latest version of After Dark ..."
meta=$(wget -qO - https://registry.npmjs.org/after-dark/latest)
vers=$(echo "$meta" | egrep -o "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
THEME_META=$(wget -qO - https://registry.npmjs.org/after-dark/latest)
vers=$(echo "$THEME_META" | egrep -o "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
mkdir -p themes/after-dark
wget -qO - https://registry.npmjs.org/after-dark/-/after-dark-"$vers".tgz | tar --strip-components=1 -xz -C themes/after-dark
echo "Version $vers downloaded to $SITE_DIR/themes/after-dark"
@ -51,6 +51,7 @@ download_module () {
configure_theme () {
echo "Configuring basic After Dark theme settings ..."
mkdir data/theme && echo -E "$THEME_META" > data/theme/latest.json
tee "config.toml" > /dev/null <<TOML
baseurl = "https://domain.example/" # Controls base URL sitewide
languageCode = "en-US" # Controls site language
@ -96,7 +97,8 @@ update_archetypes () {
generate_help_docs () {
echo "Generating help documentation ..."
hugo new post/welcome.md --kind help 1>/dev/null
mkdir data/theme && echo "$THEME_META" | tr '\r\n' ' ' > data/theme/latest.json
hugo new help/index.md --kind help 1>/dev/null
}
serve_help_docs () {

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

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

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

@ -0,0 +1,13 @@
{{ define "title" -}}
{{ .Title }} | {{ .Site.Title }}
{{- end }}
{{ define "header" }}
{{ partial "menu.html" . }}
{{ end }}
{{ define "main" }}
{{ partial "toc-maybe.html" . }}
{{ .Content }}
{{ end }}
{{ define "footer" }}
{{ partial "powered-by.html" . }}
{{ end }}

+ 1
- 1
layouts/index.html View File

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

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

@ -0,0 +1,65 @@
{{ $scratch := newScratch }}
{{ range where .Site.RegularPages "Type" "help" }}
{{ $scratch.Set "sha512" .Params.installation.sha512 }}
{{ end }}
{{ if $scratch.Get "sha512" }}
<script>
(function (window, document, undefined) {
"use strict";
const sha512 = '{{ $scratch.Get "sha512" }}';
const confirm = fragment => {
document.body.insertBefore(fragment, document.body.firstChild);
const form = document.forms.validate;
form.sha512.type = 'password';
form.sha512.value = sha512;
form.validation.classList.add('form-success');
form.validation.disabled = true;
const message = "Signature verified. Valid installation detected."
form.querySelector('.help-block').innerHTML = message;
};
const validate = (search, form) => {
search.includes(encodeURIComponent(sha512)) ? confirm(form) : challenge(form);
};
const challenge = fragment => {
const body = document.body;
if (body.firstChild === document.forms.validate) return;
while (body.firstChild) body.removeChild(body.firstChild);
body.insertBefore(fragment, body.firstChild);
const form = document.forms.validate;
form.sha512.value = sha512;
const check = () => {
const classes = form.validation.classList;
if (form.checkValidity()) {
classes.add('form-success');
classes.remove('form-warning');
} else {
classes.add('form-warning');
classes.remove('form-success');
}
};
form.oninput = check;
document.location.pathname !== '/' && (() => {
form.validation.classList.add('form-error');
document.title = "Invalid | {{ .Site.Title }}";
const help = form.querySelector('.help-block');
help.innerHTML = help.innerText = "Signature invalid. Please try again.";
const alert = document.createElement('div');
alert.classList.add('alert');
alert.classList.add('alert-warning');
alert.innerHTML = '<strong>WARNING</strong> Bad digest detected. Installation may be corrupt.';
document.body.appendChild(alert);
})();
};
const initialize = () => {
const fragment = document.createDocumentFragment();
fragment.appendChild(document.forms.validate);
(document.location.search.replace('?sha512=','').length)
? validate(location.search, fragment)
: challenge(fragment);
};
document.onreadystatechange = () => {
document.readyState === 'interactive' && initialize();
};
})(window, document);
</script>
{{ end }}

Loading…
Cancel
Save