Initial commit

This commit is contained in:
Sofía Aritz 2023-12-06 18:17:16 +01:00
parent 9c695bfd84
commit e04d8286f9
Signed by: sofia
GPG key ID: 90B5116E3542B28F
31 changed files with 947 additions and 37 deletions

View file

@ -1,15 +1,35 @@
const { DateTime } = require("luxon")
const markdownIt = require("markdown-it"); const markdownIt = require("markdown-it");
const markdownItAnchor = require("markdown-it-anchor"); const markdownItAnchor = require("markdown-it-anchor");
const timeToRead = require("eleventy-plugin-time-to-read")
module.exports = function(eleventyConfig) { module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy({ "static": "/" }) eleventyConfig.addPassthroughCopy({ "static": "/" })
eleventyConfig.addPlugin(timeToRead, {
language: "en",
style: "long",
hours: "auto",
minutes: true,
})
eleventyConfig.setLibrary("md", markdownIt({ eleventyConfig.setLibrary("md", markdownIt({
html: true html: true
}).use(markdownItAnchor, { }).use(markdownItAnchor, {
level: 2 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 { return {
passthroughFileCopy: true, passthroughFileCopy: true,
dir: { dir: {

View file

@ -1,14 +1,5 @@
# Eleventy Base # sofi web
A template for creating [11ty](https://www.11ty.dev/docs/) websites. My personal website :)
## Getting started [sofiaritz.com](https://sofiaritz.com)
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.

View file

@ -8,6 +8,8 @@
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"@11ty/eleventy": "^2.0.1", "@11ty/eleventy": "^2.0.1",
"eleventy-plugin-time-to-read": "^1.3.0",
"luxon": "^3.4.4",
"markdown-it": "^13.0.2", "markdown-it": "^13.0.2",
"markdown-it-anchor": "^8.6.7" "markdown-it-anchor": "^8.6.7"
}, },

View file

@ -5,25 +5,76 @@
<meta name="viewport" <meta name="viewport"
content="width=device-width, user-scalable=yes, initial-scale=1.0, minimum-scale=1.0"> content="width=device-width, user-scalable=yes, initial-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="/css/base.css" rel="stylesheet"> <link href="https://cdn.sofiaritz.com" rel="preconnect" crossorigin>
<title>{% if title %} {{ title }} - {% endif %}11ty base</title> <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> </head>
<body> <body>
<h1><a href="/">11TY BASE</a></h1> <h1><a href="/">sofi web</a></h1>
<div class="page-container"> <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> <main>
{{ content | safe }} {{ content | safe }}
</main> </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>
<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> </body>
</html> </html>

45
src/_includes/post.njk Normal file
View 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
View 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
View 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`.

View file

@ -2,12 +2,23 @@
layout: base_page.njk 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 Pese a ser una estudiante estoy trabajando en algunos [proyectos](/proyectos) centrados en la creación de herramientas
the colors to suit your style. 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
View 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
View 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)

View 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
View 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.

View 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.

View 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!

View 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
:)

View 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
View 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
View 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
View 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>

View file

@ -0,0 +1,7 @@
---
layout: base_page.njk
---
# Tagged “archived”
[Archived](/meta/archived) posts are not listed here.

View file

@ -4,10 +4,13 @@
line-height: 24px; line-height: 24px;
font-weight: 400; font-weight: 400;
min-height: 100%; min-height: 150vh;
color: rgba(255, 255, 255, 0.9); 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; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
@ -17,7 +20,7 @@
} }
a { a {
color: #b8c3de; color: #e74cac;
} }
body { body {
@ -27,23 +30,29 @@ body {
body > h1 { body > h1 {
font-size: 50px; font-size: 50px;
text-align: center; text-align: center;
font-family: "Nunito", "Rubik", Inter, Avenir, Helvetica, Arial, sans-serif;
} }
body > h1 > a { body > h1 > a {
color: #fafafa; color: #fafafa;
text-decoration: underline; text-decoration: underline;
text-decoration-color: #2c9ad5; text-decoration-color: #d52c9c;
} }
main { main {
width: 40vw; width: 40vw;
margin-bottom: 75px; text-align: justify;
padding: 1rem;
background-color: rgba(10, 10, 10, 0.35);
border-radius: 5px;
} }
.page-container { .page-container {
display: flex; display: flex;
margin: 0 10px; margin: 0 10px;
gap: 15px; gap: 15px;
flex-direction: row-reverse;
justify-content: center; justify-content: center;
} }
@ -76,8 +85,9 @@ nav div ul a {
margin: 10px 0; margin: 10px 0;
transition: all 150ms; transition: all 150ms;
background-color: #686b77; background-color: #dc3f99;
border: solid 3px #2c9ad5; border: solid 3px;
border-color: #f38cc2 #dc158d #dc158d #f38cc2;
color: white; color: white;
} }

View 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;
}

View 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;
}

File diff suppressed because one or more lines are too long

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View 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
}
})()

View file

@ -459,6 +459,11 @@ ejs@^3.1.9:
dependencies: dependencies:
jake "^10.8.5" 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: encodeurl@~1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 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" resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.3.tgz#8ddf0358a9492267ffec6a13675fbaab5551315d"
integrity sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg== 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: markdown-it-anchor@^8.6.7:
version "8.6.7" version "8.6.7"
resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634" resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634"