From 427ffc7241b32aba85f3dee67a2d371bb1c21420 Mon Sep 17 00:00:00 2001 From: welpo Date: Fri, 18 Aug 2023 18:39:24 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(footer/socials):=20add=20base6?= =?UTF-8?q?4=20encoded=20email=20protection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.toml | 8 +++++++ content/blog/javascript.ca.md | 13 ++++++++-- content/blog/javascript.es.md | 13 ++++++++-- content/blog/javascript.md | 13 ++++++++-- static/js/decodeMail.js | 44 ++++++++++++++++++++++++++++++++++ static/js/decodeMail.min.js | 1 + templates/partials/footer.html | 33 +++++++++++++++++++++++++ 7 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 static/js/decodeMail.js create mode 100644 static/js/decodeMail.min.js diff --git a/config.toml b/config.toml index f72bcc0..d974545 100644 --- a/config.toml +++ b/config.toml @@ -208,6 +208,14 @@ menu = [ # The RSS icon will be shown if (1) it's enabled and (2) the following variable is set to true. feed_icon = true +# Email address for footer's social section. +# Protect against spambots: +# 1. Use base64 for email (convert at https://www.base64encode.org/ or `printf 'your@email.com' | base64`). +# 2. Or, set 'encode_plaintext_email' to true for auto-encoding (only protects on site, not in public repos). +email = "bWFpbEBleGFtcGxlLmNvbQ==" # base64 encoded version of "mail@example.com" +# Decoding requires ~400 bytes of JavaScript. If JS is disabled, the email won't be displayed. +encode_plaintext_email = true # Setting is ignored if email is already encoded. + # The icons available can be found in "social_icons" in the "static" folder. socials = [ { name = "github", url = "https://github.com/welpo/", icon = "github" }, diff --git a/content/blog/javascript.ca.md b/content/blog/javascript.ca.md index 22c0433..2ed512c 100644 --- a/content/blog/javascript.ca.md +++ b/content/blog/javascript.ca.md @@ -1,18 +1,23 @@ +++ title = "Sense JavaScript obligatori" date = 2023-01-06 -updated = 2023-08-02 +updated = 2023-08-18 description = "JavaScript només s'utilitza quan HTML i CSS no són suficients." [taxonomies] tags = ["funcionalitat", "tutorial"] + +[extra] +footnote_backlinks = true +++ Aquest tema no requereix JavaScript obligatori. Opcionalment, pot carregar una quantitat mínima per afegir algunes característiques que són impossibles d'aconseguir amb HTML i CSS. ## Opcions habilitades globalment -L'**interruptor de mode clar/fosc** pot habilitar-se configurant `theme_switcher = true` a la secció `[extra]` del teu `config.toml` (~900 bytes de JavaScript). +- L'**interruptor de mode clar/fosc** pot habilitar-se configurant `theme_switcher = true` a la secció `[extra]` del teu `config.toml` (~900 bytes de JavaScript). + +- **Decodificació del correu** (~400 bytes). Per protegir el teu lloc correu dels [robots de correu brossa](https://ca.wikipedia.org/wiki/Robot_de_correu_brossa), pots configurar `encode_plaintext_email = true`. Si el teu lloc web està en un repositori públic, per a una protecció millorada, considera configurar el teu `email` com una cadena codificada en base64[^1] directament (per exemple: `email = "bWFpbEBleGFtcGxlLmNvbQ=="`). ## Configuracions que es poden habilitar tant globalment com en publicacions individuals @@ -28,3 +33,7 @@ Per habilitar aquestes configuracions globalment, afegeix-les a la secció `[ext - [**Comentaris**](@/blog/comments.ca.md). giscus (2 KB), utterances (1 KB), Hyvor Talk (~800 bytes) o Isso (1KB) es poden habilitar globalment configurant `enabled_for_all_posts = true` a la secció apropiada del teu fitxer `config.toml` (`[extra.giscus]`, `[extra.utterances]`, `[extra.hyvortalk]` o `[extra.isso]`). Per habilitar comentaris en publicacions individuals, configura el nom del sistema `= true` (per exemple, `hyvortalk = true`) al front matter del post. A part d'això, és un tema ràpid amb HTML i CSS que funciona sense JavaScript. Just com hauria de ser (la majoria de) la web :-) + +
+ +[^1]: Per codificar el teu correu en base64 pots utilitzar [eines en línia](https://www.base64encode.org/) o, al terminal, executa: `printf 'mail@example.com' | base64`. diff --git a/content/blog/javascript.es.md b/content/blog/javascript.es.md index c85a22f..297140b 100644 --- a/content/blog/javascript.es.md +++ b/content/blog/javascript.es.md @@ -1,18 +1,23 @@ +++ title = "Sin JavaScript obligatorio" date = 2023-01-06 -updated = 2023-08-02 +updated = 2023-08-18 description = "JavaScript solo se utiliza cuando HTML y CSS no son suficientes." [taxonomies] tags = ["funcionalidad", "tutorial"] + +[extra] +footnote_backlinks = true +++ Este tema no tiene JavaScript obligatorio. Opcionalmente, puede cargar una cantidad mínima para agregar algunas características que son imposibles de lograr con HTML y CSS. ## Opciones habilitadas globalmente -El **interruptor de modo claro/oscuro** puede habilitarse configurando `theme_switcher = true` en la sección `[extra]` de tu `config.toml` (~900 bytes de JavaScript). +- El **interruptor de modo claro/oscuro** puede habilitarse configurando `theme_switcher = true` en la sección `[extra]` de tu `config.toml` (~900 bytes de JavaScript). + +- **Decodificación de correo electrónico** (~400 bytes). Para protegerte contra los bots que escanean tu correo electrónico desde tu sitio web, puedes configurar `encode_plaintext_email = true`. Si tu sitio está en un repositorio público, para una protección extra, considera configurar tu `email` como una cadena codificada en base64[^1] directamente. ## Configuraciones que pueden habilitarse tanto globalmente como en publicaciones individuales @@ -27,3 +32,7 @@ Para habilitar estas configuraciones globalmente, añádelas en la sección `[ex - [**Comentarios**](@/blog/comments.es.md). giscus (2 KB), utterances (1 KB), Hyvor Talk (~800 bytes) o Isso (1KB) se pueden habilitar globalmente configurando `enabled_for_all_posts = true` en el apartado apropiado de tu archivo `config.toml` (`[extra.giscus]`, `[extra.utterances]`, `[extra.hyvortalk]` o `[extra.isso]`). Para habilitar comentarios en publicaciones individuales, configura el nombre del sistema `= true` (por ejemplo, `hyvortalk = true`) en el front matter del post. Aparte de eso, es un tema rápido con HTML y CSS que funciona con JavaScript deshabilitado. Justo como debería ser (en su mayoría) la web :-) + +
+ +[^1]: Para codificar tu correo en base64 puedes usar [herramientas en línea](https://www.base64encode.org/) o, en tu terminal, ejecuta: `printf ' diff --git a/content/blog/javascript.md b/content/blog/javascript.md index 29fe968..36f3bc9 100644 --- a/content/blog/javascript.md +++ b/content/blog/javascript.md @@ -1,18 +1,23 @@ +++ title = "No mandatory JavaScript" date = 2023-01-06 -updated = 2023-08-02 +updated = 2023-08-18 description = "JavaScript is only used when HTML and CSS aren't enough." [taxonomies] tags = ["showcase", "tutorial"] + +[extra] +footnote_backlinks = true +++ This theme has no mandatory JavaScript. Optionally, it can load a minimal amount to add some features that are impossible to achieve with HTML and CSS. ## Globally enabled settings -The **light/dark mode switch** can be enabled by setting `theme_switcher = true` in the `[extra]` section of your `config.toml` (~900 bytes of JavaScript). +- The **light/dark mode switch** can be enabled by setting `theme_switcher = true` in the `[extra]` section of your `config.toml` (~900 bytes of JavaScript). + +- **E-mail decoding** (~400 bytes). To protect against spambots scraping your e-mail from your website, you can set `encode_plaintext_email = true`. If your site is on a public repository, for extra protection, consider setting your `email` as a base64-encoded string[^1] directly. ## Settings that can be enabled globally and for individual posts @@ -27,3 +32,7 @@ To enable these settings globally, add them in the `[extra]` section of your `co - [**Comments**](@/blog/comments.md). giscus (2 KB), utterances (1 KB), Hyvor Talk (~800 bytes) or Isso (1KB) can be globally enabled by setting `enabled_for_all_posts = true` in the right section of your `config.toml` (i.e. `[extra.giscus]`, `[extra.utterances]`, `[extra.hyvortalk]` or `[extra.isso]`). To enable comments on individual posts, set the name of the system `= true` (e.g. `hyvortalk = true`) in the post's front matter. Other than that, it's a fast theme with HTML and CSS which works with JavaScript disabled. Just the way (most of) the web should be :-) + +
+ +[^1]: To encode your email in base64 you can use [online tools](https://www.base64encode.org/) or, on your terminal, run: `printf 'mail@example.com' | base64`. diff --git a/static/js/decodeMail.js b/static/js/decodeMail.js new file mode 100644 index 0000000..d62c70c --- /dev/null +++ b/static/js/decodeMail.js @@ -0,0 +1,44 @@ +(function () { + 'use strict'; + + // Utility function: Base64 Decoding. + function decodeBase64(encodedString) { + try { + // Can't use atob() directly because it doesn't support non-ascii characters. + // And non-ascii characters are allowed in email addresses and domains. + // See https://en.wikipedia.org/wiki/Email_address#Internationalization + // Code below adapted from Jackie Han: https://stackoverflow.com/a/64752311 + const byteString = atob(encodedString); + + // Convert byteString to an array of char codes. + const charCodes = [...byteString].map(char => char.charCodeAt(0)); + + // Use TypedArray.prototype.set() to copy the char codes into a Uint8Array. + const bytes = new Uint8Array(charCodes.length); + bytes.set(charCodes); + + const decoder = new TextDecoder("utf-8"); + return decoder.decode(bytes); + } catch (e) { + console.error("Failed to decode Base64 string: ", e); + return null; + } + } + + // Utility function: Update href of an element with a decoded email. + function updateEmailHref(element) { + const encodedEmail = element.getAttribute('data-encoded-email'); + const decodedEmail = decodeBase64(encodedEmail); + + if (decodedEmail) { + element.setAttribute('href', `mailto:${decodedEmail}`); + } else { + // If the decoding fails, hide the email link. + element.style.display = 'none'; + } + } + + // Fetch and process email elements with the "data-encoded-email" attribute. + const encodedEmailElements = document.querySelectorAll('[data-encoded-email]'); + encodedEmailElements.forEach(updateEmailHref); +})(); diff --git a/static/js/decodeMail.min.js b/static/js/decodeMail.min.js new file mode 100644 index 0000000..2b766a0 --- /dev/null +++ b/static/js/decodeMail.min.js @@ -0,0 +1 @@ +!function(){"use strict";document.querySelectorAll("[data-encoded-email]").forEach(function(e){var t=function(e){try{var t=[...atob(e)].map(e=>e.charCodeAt(0)),r=new Uint8Array(t.length);return r.set(t),new TextDecoder("utf-8").decode(r)}catch(e){return console.error("Failed to decode Base64 string: ",e),null}}(e.getAttribute("data-encoded-email"));t?e.setAttribute("href","mailto:"+t):e.style.display="none"})}(); diff --git a/templates/partials/footer.html b/templates/partials/footer.html index 35d6f17..bc0dd04 100644 --- a/templates/partials/footer.html +++ b/templates/partials/footer.html @@ -10,6 +10,34 @@ {%- endif -%} + + {# Mail icon #} + {%- if config.extra.email -%} + {%- set email_already_encoded = (config.extra.email is not containing("@")) -%} + {%- set email_needs_decoding = email_already_encoded or config.extra.encode_plaintext_email -%} + + {%- if email_already_encoded -%} + {%- set encoded_email = config.extra.email -%} + {# Verify the pre-encoded e-mail is valid (i.e. contains an '@') #} + {%- set decoded_email = encoded_email | base64_decode -%} + {%- if '@' not in decoded_email -%} + {{ throw(message="ERROR: The provided e-mail appears to be base64-encoded, but does not decode to a valid e-mail address.")}} + {%- endif -%} + {%- elif config.extra.encode_plaintext_email -%} + {%- set encoded_email = config.extra.email | base64_encode -%} + {%- endif -%} + +
  • + {%- if email_needs_decoding -%} + +
  • + {%- endif -%} + {% for social in config.extra.socials %}
  • Zola {%- if lang != config.default_language %} {{ trans(key="and" | safe, lang=lang) }} {% else %} & {% endif %} tabi + + {# Load the decoding script if email is encoded #} + {%- if email_needs_decoding -%} + + {%- endif -%}