generated from sofia/eleventy-base
Initial commit
This commit is contained in:
parent
9c695bfd84
commit
e04d8286f9
31 changed files with 947 additions and 37 deletions
20
.eleventy.js
20
.eleventy.js
|
@ -1,15 +1,35 @@
|
|||
const { DateTime } = require("luxon")
|
||||
const markdownIt = require("markdown-it");
|
||||
const markdownItAnchor = require("markdown-it-anchor");
|
||||
const timeToRead = require("eleventy-plugin-time-to-read")
|
||||
|
||||
module.exports = function(eleventyConfig) {
|
||||
eleventyConfig.addPassthroughCopy({ "static": "/" })
|
||||
|
||||
eleventyConfig.addPlugin(timeToRead, {
|
||||
language: "en",
|
||||
style: "long",
|
||||
hours: "auto",
|
||||
minutes: true,
|
||||
})
|
||||
|
||||
eleventyConfig.setLibrary("md", markdownIt({
|
||||
html: true
|
||||
}).use(markdownItAnchor, {
|
||||
level: 2
|
||||
}))
|
||||
|
||||
eleventyConfig.addFilter("relevantTags", tags => tags.filter(v => !["archived", "post"].includes(v)))
|
||||
|
||||
eleventyConfig.addFilter("readableDate", dateObj => {
|
||||
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).setLocale("es-ES").toFormat("dd LLL yyyy");
|
||||
})
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
|
||||
eleventyConfig.addFilter('htmlDateString', dateObj => {
|
||||
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('yyyy-LL-dd');
|
||||
})
|
||||
|
||||
return {
|
||||
passthroughFileCopy: true,
|
||||
dir: {
|
||||
|
|
15
README.md
15
README.md
|
@ -1,14 +1,5 @@
|
|||
# Eleventy Base
|
||||
# sofi web
|
||||
|
||||
A template for creating [11ty](https://www.11ty.dev/docs/) websites.
|
||||
My personal website :)
|
||||
|
||||
## Getting started
|
||||
|
||||
Run `yarn` to resolve the dependencies.
|
||||
|
||||
Make sure to check the following files and change them according to your needs:
|
||||
* [src/_includes/base_page.njk](src/_includes/base_page.njk). This is the base page, you should change the title of the
|
||||
page.
|
||||
* [static/css/base.css](static/css/base.css). This is the base theme, you should at least change the colors.
|
||||
|
||||
After changing the files, run `yarn serve` to serve the website.
|
||||
[sofiaritz.com](https://sofiaritz.com)
|
|
@ -8,6 +8,8 @@
|
|||
"private": true,
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^2.0.1",
|
||||
"eleventy-plugin-time-to-read": "^1.3.0",
|
||||
"luxon": "^3.4.4",
|
||||
"markdown-it": "^13.0.2",
|
||||
"markdown-it-anchor": "^8.6.7"
|
||||
},
|
||||
|
|
|
@ -5,25 +5,76 @@
|
|||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=yes, initial-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link href="/css/base.css" rel="stylesheet">
|
||||
<title>{% if title %} {{ title }} - {% endif %}11ty base</title>
|
||||
<link href="https://cdn.sofiaritz.com" rel="preconnect" crossorigin>
|
||||
<link href="/assets/css/fonts.css" rel="stylesheet">
|
||||
<link href="/assets/css/base.css" rel="stylesheet">
|
||||
{% if styles %}
|
||||
{% for style in styles %}
|
||||
<link href="{{ style }}" rel="stylesheet">
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<title>{% if title %} {{ title }} - {% endif %}sofi web</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1><a href="/">11TY BASE</a></h1>
|
||||
<h1><a href="/">sofi web</a></h1>
|
||||
<div class="page-container">
|
||||
<nav>
|
||||
<div>
|
||||
<i>main</i>
|
||||
<ul>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/">home 1</a></li>
|
||||
<li><a href="/">home 2</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
{{ content | safe }}
|
||||
</main>
|
||||
<nav>
|
||||
{% if lang != "en" %}
|
||||
<div>
|
||||
<i>yo</i>
|
||||
<ul>
|
||||
<li><a href="/">inicio y sobre mí</a></li>
|
||||
<li><a href="/contacto">contacto</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<i>creaciones</i>
|
||||
<ul>
|
||||
<li><a href="/weblog">weblog</a></li>
|
||||
<li><a href="/proyectos">proyectos</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div>
|
||||
<i>me</i>
|
||||
<ul>
|
||||
<li><a href="/en/contact">contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<i>creations</i>
|
||||
<ul>
|
||||
<li><a href="/en/weblog">weblog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<i>links</i>
|
||||
<ul>
|
||||
<li><a href="https://status.sofiaritz.com">status</a></li>
|
||||
<li><a href="https://git.sofiaritz.com/explore/repos">forgejo</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<i>global</i>
|
||||
<ul>
|
||||
<li><a href="/en/contact">english</a></li>
|
||||
<li><a href="/">spanish</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
{% if scripts %}
|
||||
{% for script in scripts %}
|
||||
<script src="{{ script }}"></script>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
45
src/_includes/post.njk
Normal file
45
src/_includes/post.njk
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
scripts: ["/assets/weblog/comments.js", "/assets/libraries/dompurify.js"]
|
||||
styles: ["/assets/css/comments.css"]
|
||||
---
|
||||
|
||||
<h1>{{ title }}</h1>
|
||||
<div style="display: inline">
|
||||
{% if date %}
|
||||
<time datetime="{{ date | htmlDateString }}">{{ date | readableDate }}</time> |
|
||||
{% endif %}
|
||||
|
||||
{% if tags.includes("archived") %}
|
||||
<span><a href="/meta/archived">Archived post</a></span> |
|
||||
{% endif %}
|
||||
|
||||
{% if tags %}
|
||||
{% if tags.length > 1 %}
|
||||
<span>Tags:</span>
|
||||
{% else %}
|
||||
<span>Tag:</span>
|
||||
{% endif %}
|
||||
{% set relTags = tags | relevantTags %}
|
||||
{% for tag in relTags %}
|
||||
<span><a href="/weblog/tags/{{ tag }}">{{ tag }}</a> {% if loop.last == false %}·{% endif %}</span>
|
||||
{% endfor %}
|
||||
|
|
||||
{% endif %}
|
||||
{{ content | timeToRead }} |
|
||||
<a href="#comments">Comments</a>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
{% if comment_status %}
|
||||
<hr>
|
||||
<div id="comments">
|
||||
<div>
|
||||
<h2 style="display: inline">comments · <a href="https://hachyderm.io/@sofiaritz/{{ comment_status }}">post</a></h2>
|
||||
</div>
|
||||
<section data-status="{{ comment_status }}" id="comment-section"></section>
|
||||
</div>
|
||||
{% endif %}
|
25
src/contact.md
Normal file
25
src/contact.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: contact
|
||||
permalink: /en/contact.html
|
||||
lang: "en"
|
||||
---
|
||||
|
||||
# contact
|
||||
|
||||
### direct contact
|
||||
|
||||
* E-mail: [sofi@sofiaritz.com](mailto:sofi@sofiaritz.com)
|
||||
* Matrix: [@sofiaritz:matrix.org](https://matrix.to/#/@sofiaritz:matrix.org)
|
||||
|
||||
### social media
|
||||
|
||||
* Forgejo: [sofia@git.sofiaritz.com](https://git.sofiaritz.com/sofia)
|
||||
* Fediverse: [@me@sofiaritz.com](https://hachyderm.io/@sofiaritz) (@sofiaritz@hachyderm.io)
|
||||
|
||||
### encryption and signing
|
||||
|
||||
You can find my public PGP key at [/keys/pub.asc](/keys/pub.asc), it's also available at the
|
||||
[Ubuntu keyservers](https://keyserver.ubuntu.com/).
|
||||
|
||||
The fingerprint of the cert is: `4BB1 6A74 5DE1 C776 5CF3 8788 90B5 116E 3542 B28F`.
|
26
src/contacto.md
Normal file
26
src/contacto.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: contacto
|
||||
permalink: /contact.html
|
||||
---
|
||||
|
||||
# contacto
|
||||
|
||||
Si tienes interés en trabajar conmigo, visita mi [página de trabajo](https://work.sofiaritz.com/).
|
||||
|
||||
### contacto directo
|
||||
|
||||
* Correo electrónico: [sofi@sofiaritz.com](mailto:sofi@sofiaritz.com)
|
||||
* Matrix: [@sofiaritz:matrix.org](https://matrix.to/#/@sofiaritz:matrix.org)
|
||||
|
||||
### redes sociales
|
||||
|
||||
* Forgejo: [sofia@git.sofiaritz.com](https://git.sofiaritz.com/sofia)
|
||||
* Fediverse: [@me@sofiaritz.com](https://hachyderm.io/@sofiaritz) (@sofiaritz@hachyderm.io)
|
||||
|
||||
### cifrado y firma
|
||||
|
||||
Puedes encontrar mi clave PGP pública en [/keys/pub.asc](/keys/pub.asc), también disponible en los
|
||||
[keyservers de Ubuntu](https://keyserver.ubuntu.com/).
|
||||
|
||||
La huella digital del certificado es: `4BB1 6A74 5DE1 C776 5CF3 8788 90B5 116E 3542 B28F`.
|
21
src/index.md
21
src/index.md
|
@ -2,12 +2,23 @@
|
|||
layout: base_page.njk
|
||||
---
|
||||
|
||||
# eleventy base
|
||||
# inicio
|
||||
|
||||
This is a template for creating [11ty](https://www.11ty.dev/docs/) websites.
|
||||
Soy Sofía, aunque la gente me suele llamar Sofi.
|
||||
|
||||
The default theme isn't beautiful, but it isn't meant to be. Head over to the `static/css/base.css` file and change
|
||||
the colors to suit your style.
|
||||
Pese a ser una estudiante estoy trabajando en algunos [proyectos](/proyectos) centrados en la creación de herramientas
|
||||
para ayudar a desarrolladores crear sistemas más privados y seguros. Además de esto, colaboro en algunos proyectos cuyo
|
||||
objetivo es devolver a los usuarios el control sobre sus datos.
|
||||
|
||||
Make sure to check the `src/_includes/base_page.njk` to change things like the title and stuff like that.
|
||||
Trato de usar e impulsar el uso de [estándares abiertos](https://es.wikipedia.org/wiki/Est%C3%A1ndar_abierto) y
|
||||
sistemas [descentralizados](https://es.wikipedia.org/wiki/Descentralizaci%C3%B3n), ya que se alinean con mis
|
||||
[objetivos](https://work.sofiaritz.com/objetivos/) a la hora de crear software.
|
||||
|
||||
Además del mundo de la computación, tengo un especial interés en el mundo lingüístico, en especial en
|
||||
las [lenguas construidas](https://es.wikipedia.org/wiki/Lengua_construida) y el
|
||||
[Toki Pona](https://es.wikipedia.org/wiki/Toki_pona).
|
||||
|
||||
En lo que respecta a las tecnologías que suelo manejar, todo depende del proyecto y sus especificaciones, pero tiendo
|
||||
a centrarme en [Rust](https://es.wikipedia.org/wiki/Rust_(lenguaje_de_programaci%C3%B3n)) o [Zig](https://ziglang.org/)
|
||||
y [JavaScript](https://es.wikipedia.org/wiki/JavaScript). Este es un indicador muy simple, pues cada lenguaje
|
||||
tiene distintas ramificaciones, pero esta página de inicio no es el lugar para detallar el uso que le doy a cada uno.
|
||||
|
|
15
src/meta/archived.md
Normal file
15
src/meta/archived.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: archived
|
||||
---
|
||||
|
||||
# archived pages
|
||||
|
||||
Archived pages are left for historical purposes, but should be taken with a grain of salt.
|
||||
|
||||
Archived pages _could_ contain the following problems:
|
||||
* Their content is not up-to-date.
|
||||
* Their content is not accurate.
|
||||
* They do not represent my current views or opinions.
|
||||
* They contain broken links, images, etc.
|
||||
* If you find any of these, [contact me](/contacto), and I'll do my best to fix it.
|
12
src/meta/index.md
Normal file
12
src/meta/index.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: meta
|
||||
---
|
||||
|
||||
# meta
|
||||
|
||||
The purpose of this page is to serve as an index to the various documents related to non-technical aspects of the
|
||||
projects I maintain.
|
||||
|
||||
* [archived pages](/meta/archived)
|
||||
* [maintenance tiers](/meta/maintenance-tiers)
|
54
src/meta/maintenance-tiers.md
Normal file
54
src/meta/maintenance-tiers.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: maintenance tiers
|
||||
---
|
||||
|
||||
# maintenance tiers
|
||||
|
||||
Not all projects are treated equal. Some are in active development, others are finished, others are deprecated, etc.
|
||||
|
||||
The purpose of this page is to show what does each tier mean. Some projects may not adhere to the descriptions here,
|
||||
any deviation from this page _should_ be documented in the project itself.
|
||||
|
||||
## active development
|
||||
|
||||
**Recommendation:** feel free to use the project.
|
||||
|
||||
* The project is not finished yet and new features will arrive in the future.
|
||||
* The response time to issues and pull requests is good.
|
||||
* New features are welcome after some public discussion.
|
||||
|
||||
## finished
|
||||
|
||||
**Recommendation:** feel free to use the project.
|
||||
|
||||
* The project serves its purpose and does not need any more features.
|
||||
* The response time to issues and pull requests is good, but those related to new features _may_ be rejected.
|
||||
* Any unexpected behaviour will be fixed by myself (unless a pull request is sent by someone else).
|
||||
|
||||
## low maintenance
|
||||
|
||||
**Recommendation:** feel free to use the project.
|
||||
|
||||
* The project serves its purpose and does not need any more features, but its relevance has decreased.
|
||||
* The response time to issues and pull requests _can_ be worse.
|
||||
* Pull requests related to new features _will_ be rejected.
|
||||
* I will not work on any non-security issues, but will review and merge pull requests.
|
||||
* Anyone can become a maintainer after [contacting me](/contacto).
|
||||
|
||||
## deprecated
|
||||
|
||||
**Recommendation:** switch to an alternative or start maintaining your own fork.
|
||||
|
||||
* The project is not actively maintained anymore.
|
||||
* I will not work on any issues, but I will review and merge pull requests related to security issues.
|
||||
* Feel free to maintain your own fork.
|
||||
|
||||
## decommissioned/archived
|
||||
|
||||
**Recommendation:** switch to an alternative or start maintaining your own fork **as soon as possible**.
|
||||
|
||||
* The project is not maintained at all.
|
||||
* I will not work on any issues.
|
||||
* Pull requests will not be reviewed nor merged.
|
||||
* Feel free to maintain your own fork.
|
22
src/proyectos.md
Normal file
22
src/proyectos.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: proyectos
|
||||
---
|
||||
|
||||
# proyectos
|
||||
|
||||
## GFonts
|
||||
|
||||
[GFonts](https://git.sofiaritz.com/GFonts) es un proyecto cuyo objetivo es proveer una serie de herramientas que en
|
||||
su conjunto ofrezcan una alternativa de código abierto y
|
||||
[_autohospedada_](https://en.wikipedia.org/wiki/Self-hosting_(web_services)) de
|
||||
[Google Fonts](https://fonts.google.com/).
|
||||
|
||||
El proyecto sigue en desarrollo, y aún no existe un post que resuma los objetivos, motivaciones e ideas del proyecto
|
||||
de una manera sistemática. Mientras tanto, puedes visitar la página en mi
|
||||
[mirror de Google Fonts](https://cdn.sofiaritz.com/fonts/) para obtener más información.
|
||||
|
||||
## otros
|
||||
|
||||
Puedes visitar mi [instancia de Forgejo](https://git.sofiaritz.com/explore/repos) para ver más proyectos míos y también
|
||||
mi [cuenta de GitHub](https://github.com/sofiaritz) para ver mis contribuciones a otros proyectos.
|
50
src/weblog/2023/11/updated-website.md
Normal file
50
src/weblog/2023/11/updated-website.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
layout: post.njk
|
||||
title: Major update
|
||||
intro: The first major update to this website and the start of a new era.
|
||||
tags:
|
||||
- meta
|
||||
- website
|
||||
- post
|
||||
- en
|
||||
date: 2023-11-28
|
||||
---
|
||||
|
||||
This website has received its first major update since
|
||||
[Jan 2, 2023](https://git.sofiaritz.com/sofia/website/commit/cce91e6649575cb2ac5a19cbe4a058115df10a5a)! The design may
|
||||
look familiar, but some things have changed:
|
||||
1. The background is a _proper_ pattern now (I still can't recall where I got the old background from)
|
||||
2. The [weblog index](/weblog) has been streamlined, and now it's the same for both the English and Spanish page.
|
||||
3. I've added support for [tags](/weblog/tags/meta/)!
|
||||
4. Some minor usability improvements.
|
||||
|
||||
There are also new additions! Support for comments has been added using the Mastodon API. Graceful degradation has
|
||||
played an important role in this remake, this website is fully viewable in the
|
||||
[Nintendo 3DS Browser](https://en.wikipedia.org/wiki/NetFront) with some minor rendering glitches.
|
||||
|
||||
The navbar has a new section: _links_, this section provides quick access to things like the
|
||||
[Status page](https://status.sofiaritz.com/) and my [Forgejo instance](https://git.sofiaritz.com/explore/repos).
|
||||
|
||||
## a new era
|
||||
|
||||
This is not only a stylistic and <abbr title="Quality of Life">QoL</abbr> change. This major change is part of the
|
||||
Common Unification Project, a project whose purpose is to develop a set of guidelines around styling, design process,
|
||||
maintenance and governance of the projects I maintain. These guidelines will be slowly added to the
|
||||
[_meta_ page](/meta).
|
||||
|
||||
[Some projects](https://status.sofiaritz.com/) have also [been deprecated](/meta/maintenance-tiers/#deprecated), which
|
||||
means that they may be [decommissioned](/meta/maintenance-tiers/#decommissioned%2Farchived) in the near future.
|
||||
|
||||
This will allow me to focus on some projects that will be released to the public in the following months.
|
||||
|
||||
## technicalities
|
||||
|
||||
This website, like the previous version, uses [11ty](https://www.11ty.dev) to prerender all the pages.
|
||||
|
||||
New weblog entries will follow the following path convention: `/weblog/YYYY/mm/<slug>`. Older posts have been
|
||||
[archived](/meta/archived).
|
||||
|
||||
## to be done
|
||||
|
||||
There are still many things to be done, like RSS feeds, improved internationalization, and
|
||||
[webmention](https://indieweb.org/Webmention) support.
|
19
src/weblog/archived/firstpost.md
Executable file
19
src/weblog/archived/firstpost.md
Executable file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
layout: post.njk
|
||||
title: Primer post
|
||||
intro: El nacimiento de mi weblog! :)
|
||||
tags:
|
||||
- meta
|
||||
- archived
|
||||
- es
|
||||
date: 2023-03-12
|
||||
permalink: /weblog/firstpost/
|
||||
---
|
||||
|
||||
Este es el primer post del weblog! Aquí iré compartiendo ideas, ocurrencias y experiencias a medida que me mueva por
|
||||
los mundos de Internet y la programación.
|
||||
|
||||
Ahora mismo este weblog está parcialmente incompleto, pero dentro de poco añadiré las cosas que faltan para que esté
|
||||
completamente a punto ([RSS](https://es.wikipedia.org/wiki/RSS), etiquetas, comentarios, etc).
|
||||
|
||||
Cualquier sugerencia o idea para este weblog podéis [enviármela](/contact) sin problema!
|
101
src/weblog/archived/note-taking-2.md
Executable file
101
src/weblog/archived/note-taking-2.md
Executable file
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
layout: post.njk
|
||||
title: Note Taking (II). Retos
|
||||
intro: Retos encontrados por el camino.
|
||||
tags:
|
||||
- rust
|
||||
- experimentos
|
||||
- note taking
|
||||
- archived
|
||||
- es
|
||||
date: 2023-05-06
|
||||
permalink: /weblog/note-taking-2/
|
||||
---
|
||||
|
||||
Hace unos meses comencé a crear [Note Taking](https://git.sofiaritz.com/sofia/note-taking), una aplicación cuyo
|
||||
propósito era la creación de un software que permitiera crear notas encriptadas de una manera sencilla y segura.
|
||||
|
||||
Surgió como un prototipo [sobre el que fui iterando](/weblog/note-taking-experiment) hasta llegar a lo que es hoy día:
|
||||
una plataforma relativamente estable, simple y segura para crear notas.
|
||||
|
||||
Pese a que el concepto es sencillo, en la ejecución lo está todo. Y ahí se yace el propósito de este artículo: mostrar
|
||||
los retos que me he encontrado en este camino.
|
||||
|
||||
## seguridad
|
||||
|
||||
La seguridad es sin duda uno de los apartados más importantes y complejos de este software. A día de hoy el sistema
|
||||
utilizado es el siguiente:
|
||||
|
||||
<img src="/assets/weblog/archived/note-taking-2/diagram1.svg" width="100%">
|
||||
|
||||
Este sistema actualmente funciona bien:
|
||||
* Todas las contraseñas tienen una alta entropía gracias al uso de Argon2 (un [KDF](https://es.wikipedia.org/wiki/Funci%C3%B3n_de_derivaci%C3%B3n_de_clave)).
|
||||
* [pwbox](https://github.com/exonum/pwbox-rs) se encarga de encriptar las notas usando el resultado derivado de la
|
||||
contraseña original.
|
||||
|
||||
Pero ello no implica que tenga algunos problemas, en especial **la imposibilidad de cambiar contraseñas**.
|
||||
|
||||
## cambio de contraseñas
|
||||
|
||||
En un software como este, es frecuente que el usuario quiera cambiar de contraseñas ocasionalmente por variadas razones:
|
||||
cambio rutinario preventivo, contraseñas que han sido expuestas, etc.
|
||||
|
||||
El sistema actual impide que esto sea posible, pues la contraseña es la base de la encriptación. A día de hoy para poder
|
||||
cambiar la contraseña sería necesario ir nota por nota desencriptándola y reencriptándola. Esto es un proceso que puede
|
||||
parecer [sencillo](https://git.sofiaritz.com/sofia/note-taking/src/commit/c97700b29aba660ffe7b6753266d6559a84b8d01/src/password/mod.rs#L59),
|
||||
pero en cuanto el número de notas crece, una operación de este tipo se vuelve imposible de manejar.
|
||||
|
||||
### posibles soluciones
|
||||
|
||||
Existen varios caminos que se pueden tomar para solucionar esto, pero el que creo que va a ser utilizado va a ser el
|
||||
siguiente:
|
||||
|
||||
Cada nota contiene una clave única que es la utilizada para encriptar los contenidos de la misma. Esta clave única,
|
||||
antes de ser almacenada en los _metadatos_ de la nota pasa por el sistema [descrito anteriormente](#seguridad).
|
||||
|
||||
Esto permite lo siguiente:
|
||||
* Cada nota tiene su clave única de encriptación, por lo tanto, un ataque de fuerza bruta directamente en la nota pierde
|
||||
utilidad.
|
||||
* El uso de una clave de encriptación única y permanente por nota permite que el cambio de la contraseña solo tenga que
|
||||
afectar a un centenar de bits en lugar de varios miles de bits, pues únicamente habría que reencriptar la clave de
|
||||
cada nota.
|
||||
|
||||
## metadatos
|
||||
|
||||
A día de hoy, todos los metadatos (título, metadatos explícitos, fecha, etc) están sin encriptar. Esto es algo bastante
|
||||
delicado, pues muchas veces los metadatos son mucho más _dañinos_ de lo que nos podemos imaginar.
|
||||
|
||||
Tengo pensado crear un archivo especial para las notas que pueda contener todas las notas de una manera centralizada
|
||||
y segura. En un principio una nota tendría una estructura similar a la siguiente:
|
||||
|
||||
* Longitud de la clave encriptada
|
||||
* Clave encriptada
|
||||
* Longitud de los metadatos
|
||||
* Metadatos en JSON encriptados
|
||||
* Longitud de la nota
|
||||
* Nota encriptada
|
||||
* Checksum de la nota
|
||||
|
||||
Además de esto, el archivo estaría versionado y trataría de ser lo más escalable posible en lo que a futuros _metadatos
|
||||
especiales_ (fecha, autor, etc) respecta.
|
||||
|
||||
## riqueza
|
||||
|
||||
A día de hoy las notas son simplemente texto plano. Otra de las cosas que tengo pensadas añadir es soporte básico de
|
||||
Markdown (únicamente cosas como **negrita**, _cursiva_, ~~tachado~~, etc.)
|
||||
|
||||
Me encantaría añadir soporte para imágenes, pero usando Markdown _estándar_ es peligroso para la seguridad de los
|
||||
usuarios. Una alternativa sería aprovechar la creación de un archivo personalizado para añadir una sección de
|
||||
información arbitraria que funcionara como un [diccionario](https://en.wikipedia.org/wiki/Associative_array), donde cada
|
||||
conjunto de datos arbitrarios tuviera asociado un identificador único que pudiera ser referenciado en Markdown.
|
||||
|
||||
Pese a ello, esto abre un gran vector de ataque que habría que cuidar, por tanto, el soporte de imágenes es algo que
|
||||
seguramente tendrá que esperar.
|
||||
|
||||
## conclusión
|
||||
|
||||
Sin duda crear este software está siendo una experiencia bastante interesante que me está ayudando a aprender sobre
|
||||
seguridad computacional y muchas otras cosas.
|
||||
|
||||
A lo largo de los meses venideros trataré de implementar estas y más cosas, subiré una actualización cuando ello ocurra
|
||||
:)
|
117
src/weblog/archived/note-taking-experiment.md
Executable file
117
src/weblog/archived/note-taking-experiment.md
Executable file
|
@ -0,0 +1,117 @@
|
|||
---
|
||||
layout: post.njk
|
||||
title: Note Taking. Notas encriptadas
|
||||
intro: Un programa experimental para encriptar notas.
|
||||
tags:
|
||||
- rust
|
||||
- experimentos
|
||||
- note taking
|
||||
- archived
|
||||
- es
|
||||
date: 2023-03-12
|
||||
permalink: /weblog/note-taking-experiment/
|
||||
---
|
||||
|
||||
## motivación
|
||||
|
||||
Un día me di cuenta de que mi _setup_ para tomar notas era bastante engorroso: abría el bloc de notas, escribía, guardaba
|
||||
el .txt, abría [Kleopatra](https://www.gpg4win.org/about.html), esperaba a que se cargara la base de datos, etc.
|
||||
|
||||
No es difícil darse cuenta de que este sistema no era _el óptimo_. Por tanto, decidí embarcarme en la búsqueda de
|
||||
algún programa que cumpliera los siguientes requisitos:
|
||||
1. **Offline**. No quiero mis notas, encriptadas o no, viajando por lugares desconocidos.
|
||||
2. **Seguro**. No quiero mis notas siendo expuestas por alguna vulnerabilidad o problema de diseño.
|
||||
3. **Simple**. No quiero tener que dar mil vueltas para escribir un documento de 50 palabras.
|
||||
|
||||
Y todo lo que encontraba no cumplía todos los requisitos: o tenía _sincronización en la nube_, o la interfaz era muy
|
||||
compleja, etc.
|
||||
|
||||
Por tanto, decidí que debía arreglar esto yo misma: y así surgió
|
||||
[note taking](https://git.sofiaritz.com/sofia/note-taking).
|
||||
|
||||
## idea
|
||||
|
||||
He estado un par de semanas experimentando con un concepto relativamente simple:
|
||||
_un programa que permita crear y almacenar notas encriptadas_.
|
||||
|
||||
Este concepto es sencillo, pero la ejecución es lo importante. Me establecí una serie de objetivos que permitieran
|
||||
poder tener una base sobre la que trabajar, y estos objetivos eran los siguientes:
|
||||
- **Simple**. Una aplicación fácil de usar para todo el mundo, con y sin conocimientos.
|
||||
- **Seguro**. Las notas no deben ser susceptibles de ataques de fuerza bruta y compañía.
|
||||
- **Completo**. Se debe ofrecer una gran variedad de opciones y posibilidades a la hora de redactar y ver las notas.
|
||||
|
||||
## funcionamiento
|
||||
|
||||
note taking tiene un funcionamiento bastante sencillo. Cuando abres la aplicación ocurre lo siguiente:
|
||||
1. Te pide que introduzcas la contraseña utilizada para encriptar la "_base de datos_".
|
||||
2. Comprueba la contraseña utilizando notas existentes.
|
||||
3. Si es correcta, carga todas las notas encriptadas en memoria para ser desencriptadas bajo demanda.
|
||||
|
||||
Una vez has pasado esta etapa inicial, todo es muy intuitivo. Para añadir una nota haces click en el botón que dice
|
||||
"_want to add one note?_", para desencriptar una nota haces click en el botón que dice "_decrypt note_", etc.
|
||||
|
||||
Además de esto, el apartado de configuración actualmente tiene la opción de exportar las notas en formato JSON para
|
||||
poder ser importadas por programas compatibles con el formato. En un futuro el apartado de configuración tendrá más
|
||||
opciones, como importar notas, cambiar la contraseña y demás.
|
||||
|
||||
## seguridad
|
||||
|
||||
Recientemente, se cambió como se manejaban las contraseñas en note taking. Ahora mismo se sigue el siguiente sistema:
|
||||
1. El usuario introduce la contraseña
|
||||
2. La contraseña pasa por una función de derivación
|
||||
([KDF](https://crypto.stackexchange.com/questions/40757/key-derivation-functions-kdf-what-are-they-what-are-their-main-purposes-and))
|
||||
1. Se calcula el SHA256 de la contraseña, que se utilizará como
|
||||
[_salt_](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#salting).
|
||||
2. Se usa [Argon2](https://en.wikipedia.org/wiki/Argon2) para crear el hash de la contraseña.
|
||||
3. Se codifica el resultado en hexadecimal.
|
||||
3. Se utiliza [pwbox](https://docs.rs/pwbox/0.5.0/pwbox/) con la contraseña derivada.
|
||||
|
||||
Este sistema evita que se puedan forzar las contraseñas:
|
||||
1. Todas las contraseñas tienen gran entropía al salir del KDF.
|
||||
2. El KDF tiene gran complejidad, lo que ralentiza los ataques de fuerza bruta.
|
||||
|
||||
Además de esto, se utilizan ciertos sistemas para _sugerir_ al usuario el uso de contraseñas seguras. Un ejemplo de esto
|
||||
es cómo se le muestran al usuario tanto la longitud como entropía de la contraseña introducida con un sistema de colores
|
||||
bastante explícito que _invita_ al usuario a emplear contraseñas seguras.
|
||||
|
||||
Todo esto se puede ver en mayor detalle en
|
||||
[_Security of the encrypted notes_ · sofia@git.sofiaritz.com/note-taking#1](https://git.sofiaritz.com/sofia/note-taking/issues/1).
|
||||
|
||||
## planes de futuro
|
||||
|
||||
En el futuro me gustaría añadir un sistema "_Markdown_" básico para que se puedan añadir cosas como letra en cursiva,
|
||||
negrita, imágenes, etc.
|
||||
|
||||
Pese a que esto pueda parecer relativamente sencillo, especialmente teniendo en cuenta que
|
||||
[ya existen librerías](https://crates.io/crates/egui_commonmark) que se encargan de esto, cosas como imágenes pueden
|
||||
ser un gran vector de ataque para intentar desanonimizar u obtener información del usuario. Por tanto, esta clase de
|
||||
decisiones deben ser tomadas con mucho estudio y cautela.
|
||||
|
||||
Además de esto, me gustaría mejorar la privacidad de ciertos aspectos de las notas (metadatos, etc.) y expandir los
|
||||
ajustes.
|
||||
|
||||
## quiero probarlo!
|
||||
|
||||
Ahora mismo [no estoy distribuyendo ejecutables](https://git.sofiaritz.com/sofia/note-taking/issues/2), pero es muy
|
||||
fácil compilar el proyecto si ya tienes Rust y Cargo.
|
||||
|
||||
Si ya tienes Rust y Cargo [instalados](https://www.rust-lang.org/tools/install) y
|
||||
[actualizados](https://rust-lang.github.io/rustup/basics.html#keeping-rust-up-to-date), ejecuta los siguientes comandos:
|
||||
1. `git clone https://git.sofiaritz.com/sofia/note-taking.git`
|
||||
2. `cd note-taking`
|
||||
3. `cargo run --release`
|
||||
|
||||
(Si el último paso falla, puede que tengas que utilizar `cargo +nightly build --release`)
|
||||
|
||||
## ideas?
|
||||
|
||||
Cualquier idea es bienvenida! [Ponte en contacto conmigo](/contact) o abre una
|
||||
[issue](https://git.sofiaritz.com/sofia/note-taking/issues) en el repositorio. :)
|
||||
|
||||
## imágenes
|
||||
|
||||
<img alt="Captura de pantalla donde se muestra una entrada de texto con los valores de entropía y longitud a la derecha en color verde, indicando así valores aceptables." src="/assets/weblog/note-taking-experimental/password-prompt.png" width="85%"/>
|
||||
<img alt="Captura de pantalla donde se muestran los botones 'want to add one note?' y 'settings'" src="/assets/weblog/note-taking-experimental/top-buttons.png" width="85%"/>
|
||||
<img alt="Captura de pantalla donde se muestra la lista de notas. En cada nota se muestra el título y su derecha la fecha. Bajo el título hay un botón que indica 'decrypt note'" src="/assets/weblog/note-taking-experimental/note-list.png" width="85%"/>
|
||||
<img alt="Captura de pantalla donde se muestra el formulario de creación de notas, con diversas entradas de texto para el título, texto y metadatos. Al final hay un botón con el texto 'add note'" src="/assets/weblog/note-taking-experimental/note-creation.png" width="85%"/>
|
||||
|
30
src/weblog/en_index.njk
Normal file
30
src/weblog/en_index.njk
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: weblog
|
||||
permalink: /en/weblog.html
|
||||
lang: "en"
|
||||
---
|
||||
|
||||
<h1>weblog</h1>
|
||||
|
||||
<div>
|
||||
<span><a href="/weblog/tags/en">English posts</a></span> ·
|
||||
<span><a href="/weblog/tags/es">Spanish posts</a></span>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
{% set taglist = collections["post"] %}
|
||||
{% for post in taglist | reverse %}
|
||||
<li><a href="{{ post.url }}">{{ post.data.title }}</a>{% if post.data.intro %} · <span>{{ post.data.intro }}</span>{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<details style="margin: 0; padding: 0" open>
|
||||
<summary><h3 id="archived" style="display: inline">Archived</h3></summary>
|
||||
<ul>
|
||||
{% set taglist = collections["archived"] %}
|
||||
{% for post in taglist | reverse %}
|
||||
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
28
src/weblog/index.njk
Normal file
28
src/weblog/index.njk
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
title: weblog
|
||||
---
|
||||
|
||||
<h1>weblog</h1>
|
||||
|
||||
<div>
|
||||
<span><a href="/weblog/tags/es">Entradas en español</a></span> ·
|
||||
<span><a href="/weblog/tags/en">Entradas en inglés</a></span>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
{% set taglist = collections["post"] %}
|
||||
{% for post in taglist | reverse %}
|
||||
<li><a href="{{ post.url }}">{{ post.data.title }}</a>{% if post.data.intro %} · <span>{{ post.data.intro }}</span>{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<details style="margin: 0; padding: 0" open>
|
||||
<summary><h3 id="archived" style="display: inline">Archivado</h3></summary>
|
||||
<ul>
|
||||
{% set taglist = collections["archived"] %}
|
||||
{% for post in taglist | reverse %}
|
||||
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
22
src/weblog/tags.njk
Normal file
22
src/weblog/tags.njk
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
pagination:
|
||||
data: collections
|
||||
size: 1
|
||||
alias: tag
|
||||
filter:
|
||||
- archived
|
||||
permalink: /weblog/tags/{{ tag }}/
|
||||
---
|
||||
<h1>Tagged “{{ tag }}”</h1>
|
||||
|
||||
<p>
|
||||
Note: <a href="/meta/archived">Archived</a> posts may not be listed.
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
{% set taglist = collections[ tag ] %}
|
||||
{% for post in taglist | reverse %}
|
||||
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ol>
|
7
src/weblog/tags/archived.md
Normal file
7
src/weblog/tags/archived.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
layout: base_page.njk
|
||||
---
|
||||
|
||||
# Tagged “archived”
|
||||
|
||||
[Archived](/meta/archived) posts are not listed here.
|
|
@ -4,10 +4,13 @@
|
|||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
min-height: 100%;
|
||||
min-height: 150vh;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
|
||||
background: #29468c;
|
||||
background-color: #2d1740;
|
||||
background-image: radial-gradient(hsl(324, 80%, 55%) 0.75px, hsl(273, 48%, 20%) 0.75px), radial-gradient(hsl(324, 80%, 55%) 0.75px, hsl(273, 48%, 20%) 0.75px);
|
||||
background-size: 25px 25px;
|
||||
background-position: 10px 10px;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
|
@ -17,7 +20,7 @@
|
|||
}
|
||||
|
||||
a {
|
||||
color: #b8c3de;
|
||||
color: #e74cac;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -27,23 +30,29 @@ body {
|
|||
body > h1 {
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
font-family: "Nunito", "Rubik", Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
body > h1 > a {
|
||||
color: #fafafa;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #2c9ad5;
|
||||
text-decoration-color: #d52c9c;
|
||||
}
|
||||
|
||||
main {
|
||||
width: 40vw;
|
||||
margin-bottom: 75px;
|
||||
text-align: justify;
|
||||
|
||||
padding: 1rem;
|
||||
background-color: rgba(10, 10, 10, 0.35);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
display: flex;
|
||||
margin: 0 10px;
|
||||
gap: 15px;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
@ -76,8 +85,9 @@ nav div ul a {
|
|||
margin: 10px 0;
|
||||
|
||||
transition: all 150ms;
|
||||
background-color: #686b77;
|
||||
border: solid 3px #2c9ad5;
|
||||
background-color: #dc3f99;
|
||||
border: solid 3px;
|
||||
border-color: #f38cc2 #dc158d #dc158d #f38cc2;
|
||||
|
||||
color: white;
|
||||
}
|
39
static/assets/css/comments.css
Normal file
39
static/assets/css/comments.css
Normal file
|
@ -0,0 +1,39 @@
|
|||
.no-comments {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.comment {
|
||||
border: #382e60 solid 1px;
|
||||
border-radius: 7px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.comment-author {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
padding: 5px;
|
||||
background-color: hsl(273, 48%, 18%);
|
||||
}
|
||||
|
||||
.comment-author-image {
|
||||
border-radius: 4px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.comment-author-data {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comment-author-data > a, .comment-author-link {
|
||||
text-decoration: none;
|
||||
color: #fafafa;
|
||||
}
|
||||
|
||||
.comment-author-data > a:hover, .comment-author-link:hover {
|
||||
color: #e74cac;
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
padding: 3px 10px;
|
||||
}
|
34
static/assets/css/fonts.css
Normal file
34
static/assets/css/fonts.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
@font-face {
|
||||
font-family: "JetBrains Mono";
|
||||
src: url("https://cdn.sofiaritz.com/fonts/ofl/jetbrainsmono/JetBrainsMono-Italic[wght].ttf");
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "JetBrains Mono";
|
||||
src: url("https://cdn.sofiaritz.com/fonts/ofl/jetbrainsmono/JetBrainsMono[wght].ttf");
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Rubik";
|
||||
src: url("https://cdn.sofiaritz.com/fonts/ofl/rubik/Rubik[wght].ttf");
|
||||
font-style: normal;
|
||||
font-weight: 400 500;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Rubik";
|
||||
src: url("https://cdn.sofiaritz.com/fonts/ofl/rubik/Rubik-Italic[wght].ttf");
|
||||
font-style: italic;
|
||||
font-weight: 400 500;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Nunito";
|
||||
src: url("https://cdn.sofiaritz.com/fonts/ofl/nunito/Nunito[wght].ttf");
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
}
|
2
static/assets/libraries/dompurify.js
Normal file
2
static/assets/libraries/dompurify.js
Normal file
File diff suppressed because one or more lines are too long
124
static/assets/weblog/archived/note-taking-2/diagram1.svg
Executable file
124
static/assets/weblog/archived/note-taking-2/diagram1.svg
Executable file
|
@ -0,0 +1,124 @@
|
|||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='153' width='784' font-family='Menlo,Lucida Console,monospace'>
|
||||
<style type="text/css">
|
||||
svg {
|
||||
color: #000000;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
svg {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<g transform='translate(8,16)'>
|
||||
<path d='M 288,0 L 344,0' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 232,16 L 280,16' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 352,16 L 400,16' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 288,32 L 344,32' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 0,96 L 152,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 192,96 L 232,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 232,96 L 280,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 368,96 L 424,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 528,96 L 576,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 640,96 L 768,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 160,112 L 184,112' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 288,112 L 360,112' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 432,112 L 520,112' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 584,112 L 632,112' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 0,128 L 152,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 192,128 L 280,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 368,128 L 424,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 528,128 L 576,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 640,128 L 768,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 0,96 L 0,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 152,96 L 152,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 192,96 L 192,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 232,16 L 232,96' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 280,96 L 280,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 288,0 L 288,32' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 344,0 L 344,32' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 368,96 L 368,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 400,16 L 400,80' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 424,96 L 424,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 528,96 L 528,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 576,96 L 576,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 640,96 L 640,128' fill='none' stroke='currentColor'></path>
|
||||
<path d='M 768,96 L 768,128' fill='none' stroke='currentColor'></path>
|
||||
<polygon points='192.000000,112.000000 180.000000,106.400002 180.000000,117.599998' fill='currentColor' transform='rotate(0.000000, 184.000000, 112.000000)'></polygon>
|
||||
<polygon points='288.000000,16.000000 276.000000,10.400000 276.000000,21.600000' fill='currentColor' transform='rotate(0.000000, 280.000000, 16.000000)'></polygon>
|
||||
<polygon points='368.000000,112.000000 356.000000,106.400002 356.000000,117.599998' fill='currentColor' transform='rotate(0.000000, 360.000000, 112.000000)'></polygon>
|
||||
<path d='M 400,80 L 400,88' fill='none' stroke='currentColor'></path>
|
||||
<polygon points='416.000000,80.000000 404.000000,74.400002 404.000000,85.599998' fill='currentColor' transform='rotate(90.000000, 400.000000, 80.000000)'></polygon>
|
||||
<polygon points='528.000000,112.000000 516.000000,106.400002 516.000000,117.599998' fill='currentColor' transform='rotate(0.000000, 520.000000, 112.000000)'></polygon>
|
||||
<polygon points='640.000000,112.000000 628.000000,106.400002 628.000000,117.599998' fill='currentColor' transform='rotate(0.000000, 632.000000, 112.000000)'></polygon>
|
||||
<style>
|
||||
text {
|
||||
text-anchor: middle;
|
||||
font-family: "Menlo","Lucida Console","monospace";
|
||||
fill: currentColor;
|
||||
font-size: 1em;
|
||||
}
|
||||
</style>
|
||||
<text x='296' y='20'>S</text>
|
||||
<text x='304' y='20'>H</text>
|
||||
<text x='312' y='20'>A</text>
|
||||
<text x='320' y='20'>2</text>
|
||||
<text x='328' y='20'>5</text>
|
||||
<text x='336' y='20'>6</text>
|
||||
<text x='408' y='52'>S</text>
|
||||
<text x='416' y='52'>a</text>
|
||||
<text x='424' y='52'>l</text>
|
||||
<text x='432' y='52'>t</text>
|
||||
<text x='8' y='116'>N</text>
|
||||
<text x='16' y='116'>o</text>
|
||||
<text x='24' y='116'>t</text>
|
||||
<text x='32' y='116'>a</text>
|
||||
<text x='48' y='116'>d</text>
|
||||
<text x='56' y='116'>e</text>
|
||||
<text x='64' y='116'>s</text>
|
||||
<text x='72' y='116'>e</text>
|
||||
<text x='80' y='116'>n</text>
|
||||
<text x='88' y='116'>c</text>
|
||||
<text x='96' y='116'>r</text>
|
||||
<text x='104' y='116'>i</text>
|
||||
<text x='112' y='116'>p</text>
|
||||
<text x='120' y='116'>t</text>
|
||||
<text x='128' y='116'>a</text>
|
||||
<text x='136' y='116'>d</text>
|
||||
<text x='144' y='116'>a</text>
|
||||
<text x='200' y='116'>C</text>
|
||||
<text x='208' y='116'>o</text>
|
||||
<text x='216' y='116'>n</text>
|
||||
<text x='224' y='116'>t</text>
|
||||
<text x='232' y='116'>r</text>
|
||||
<text x='240' y='116'>a</text>
|
||||
<text x='248' y='116'>s</text>
|
||||
<text x='256' y='116'>e</text>
|
||||
<text x='264' y='116'>ñ</text>
|
||||
<text x='272' y='116'>a</text>
|
||||
<text x='376' y='116'>A</text>
|
||||
<text x='384' y='116'>r</text>
|
||||
<text x='392' y='116'>g</text>
|
||||
<text x='400' y='116'>o</text>
|
||||
<text x='408' y='116'>n</text>
|
||||
<text x='416' y='116'>2</text>
|
||||
<text x='536' y='116'>p</text>
|
||||
<text x='544' y='116'>w</text>
|
||||
<text x='552' y='116'>b</text>
|
||||
<text x='560' y='116'>o</text>
|
||||
<text x='568' y='116'>x</text>
|
||||
<text x='648' y='116'>N</text>
|
||||
<text x='656' y='116'>o</text>
|
||||
<text x='664' y='116'>t</text>
|
||||
<text x='672' y='116'>a</text>
|
||||
<text x='688' y='116'>e</text>
|
||||
<text x='696' y='116'>n</text>
|
||||
<text x='704' y='116'>c</text>
|
||||
<text x='712' y='116'>r</text>
|
||||
<text x='720' y='116'>i</text>
|
||||
<text x='728' y='116'>p</text>
|
||||
<text x='736' y='116'>t</text>
|
||||
<text x='744' y='116'>a</text>
|
||||
<text x='752' y='116'>d</text>
|
||||
<text x='760' y='116'>a</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
BIN
static/assets/weblog/archived/note-taking-experimental/note-creation.png
Executable file
BIN
static/assets/weblog/archived/note-taking-experimental/note-creation.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
static/assets/weblog/archived/note-taking-experimental/note-list.png
Executable file
BIN
static/assets/weblog/archived/note-taking-experimental/note-list.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
static/assets/weblog/archived/note-taking-experimental/password-prompt.png
Executable file
BIN
static/assets/weblog/archived/note-taking-experimental/password-prompt.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
static/assets/weblog/archived/note-taking-experimental/top-buttons.png
Executable file
BIN
static/assets/weblog/archived/note-taking-experimental/top-buttons.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
43
static/assets/weblog/comments.js
Normal file
43
static/assets/weblog/comments.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
(async () => {
|
||||
let el = document.getElementById("comment-section")
|
||||
if (el == null) {
|
||||
return
|
||||
}
|
||||
|
||||
let status_url = `https://hachyderm.io/api/v1/statuses/${el.getAttribute("data-status")}/context`
|
||||
let comments = await (await fetch(status_url)).json()
|
||||
|
||||
if (comments["descendants"] == null || comments["descendants"].length === 0) {
|
||||
el.innerHTML = `<div class="no-comments">No comments yet</div>`
|
||||
return
|
||||
}
|
||||
|
||||
for (let comment of comments["descendants"]) {
|
||||
let date = new Date(comment.created_at).toLocaleDateString(navigator.language || "en-GB", {
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})
|
||||
let sanitize = DOMPurify.sanitize
|
||||
let comment_html =
|
||||
`
|
||||
<div class="comment">
|
||||
<div class="comment-author">
|
||||
<img class="comment-author-image" src="${sanitize(comment.account.avatar)}" alt="Profile picture of ${sanitize(comment.account.display_name)}">
|
||||
<div class="comment-author-data">
|
||||
<div>
|
||||
<span class="comment-author-name"><a class="comment-author-link" href="${comment.account.url}">${sanitize(comment.account.display_name)}</a></span>
|
||||
</div>
|
||||
<a href="${sanitize(comment.uri)}"><time datetime="${sanitize(comment.created_at)}">${date}</time></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-content">
|
||||
${sanitize(comment.content)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
el.innerHTML += comment_html
|
||||
}
|
||||
})()
|
10
yarn.lock
10
yarn.lock
|
@ -459,6 +459,11 @@ ejs@^3.1.9:
|
|||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
eleventy-plugin-time-to-read@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eleventy-plugin-time-to-read/-/eleventy-plugin-time-to-read-1.3.0.tgz#17701132491b522fa013fcc103a24eafe3b56082"
|
||||
integrity sha512-EefxYZJviQbClwoQ+pXW0YsVoi3gzXJ3prJoOLO1g3n5dM17KyZh81/yyq5Inrdc2pxBz3CXsyo21kk43gK/Gg==
|
||||
|
||||
encodeurl@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
|
@ -856,6 +861,11 @@ luxon@^3.3.0:
|
|||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.3.tgz#8ddf0358a9492267ffec6a13675fbaab5551315d"
|
||||
integrity sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==
|
||||
|
||||
luxon@^3.4.4:
|
||||
version "3.4.4"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af"
|
||||
integrity sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==
|
||||
|
||||
markdown-it-anchor@^8.6.7:
|
||||
version "8.6.7"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634"
|
||||
|
|
Loading…
Reference in a new issue