added content

This commit is contained in:
Nico 2022-12-28 10:36:15 +01:00
parent bf2221b9a9
commit 9b91b02d90
79 changed files with 3053 additions and 284 deletions

View file

@ -0,0 +1,111 @@
---
title: Strong TLS certificates with acme.sh
subtitle: 384-bit of https
lang: en
slug: "acme-sh-tls-cert"
createdAt: "2022-06-08T14:24:06.000Z"
excerpt: Real cert have curves.
tags: ["security"]
---
## Disclaimer
I'm, in absolutely no regards, a security expert. I just fancy shiny new things of the interwebs.
This is why I've switched my default TLS certificates to use elliptic curve cryptography (ECC) instead of RSA. Now I have a sweet 100/100 on [tls.imirhil.fr](https://tls.imirhil.fr/)
You can learn (far) more by reading [this topic](https://crypto.stackexchange.com/questions/1190/why-is-elliptic-curve-cryptography-not-widely-used-compared-to-rsa) and its linked resources.
## Requirements
### Installing acme.sh
For automation and ease of use purposes, I'm using [acme.sh](https://github.com/acmesh-official/acme.sh)
```bash
# for using standalone mode, you might have to install as sudo
curl https://get.acme.sh | sh -s email=mail@domain.tld
```
### Changing default authority
By default, acme.sh uses ZeroSSL to sign certificates. We need to change this to Let's Encrypt because according to acme.sh, they're the only ones offering ECC capabilities.
```bash
acme.sh --set-default-ca --server letsencrypt
```
## Using your DNS api
If available, the easiest way to issue a certificate is to use the DNS api of your DNS provider. acme.sh supports [a lot](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) of DNS providers.
### Define an api key
Follow the [docs](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) for your DNS provider, usually:
```bash
export PROVIDER_Key="YOUR_API_KEY"
```
### Issue the cert
```bash
acme.sh --issue -d domain.tld --dns dns_provider --keylength ec-384
```
## Using standalone mode
If you don't have access to the DNS provider, we can use the standalone mode to spin up a temporary web server that will handle all the verifications.
Port `80` must be free.
```bash
acme.sh --issue --standalone -d domain.tld --keylength ec-384
```
## Examples
### Multi domains standalone
```bash
acme.sh --issue --standalone -d domain.tld -d www.domain.tld -d subdomain.domain.tld --keylength ec-384
```
### Wildcard domain DNS
```bash
acme.sh --issue -d domain.tld -d '*.domain.tld' --dns dns_provider --keylength ec-384
```
## Next steps
The ECC certificate alone will not grant you a high/perfect score.
### TLS version
Limit TLS version to 1.2 and 1.3 (or just 1.3 as there is only a [5% compatibility gap](https://caniuse.com/?search=tls%201.) with 1.2).
### HSTS
Use the [strict transport security](https://scotthelme.co.uk/hsts-the-missing-link-in-tls/) header.
```
Strict-Transport-Security: max-age=31536000; includeSubDomains
```
### Cipher suite
Use recent and strong ciphers. This is where my knowledge hits its limit… I'm having a really hard time understanding what to use and why.
I've based my initial choices of ciphers on [this list](https://tls.imirhil.fr/ciphers), cross referencing it with (older?) [browser compatibility](https://tls.imirhil.fr/suite).
I then asked [Aeris](https://twitter.com/aeris22), the creator of [tls.imirhil.fr](https://tls.imirhil.fr), about it and he advised me to use the following:
```
ECDHE+AES:ECDHE+CHACHA20
```
In order to achieve a perfect score, we can be a little more restrictive with:
```
ECDHE+AES256:ECDHE+CHACHA20
```

View file

@ -0,0 +1,63 @@
---
title: Filter an array against another array
subtitle: Array vs Array.
lang: en
slug: "array-vs-array"
createdAt: "2022-06-08T14:24:06.000Z"
excerpt: My peak javascript
tags: ["nuxt.js"]
---
## Context
For a project, I had to come up with a way to filter an array of objects based on another array of strings.
In other words, I needed to include every object which `user` property was found in the second array.
Here is an example:
```javascript
const skills = [
{
name: "Be awesome",
user: "Jean",
},
{
name: "Great jokes",
user: "Jacques",
},
{
name: "Heavy sleeper",
user: "Jean",
},
{
name: "Heavy sleeper",
user: "Beatriz",
},
];
const selectedUsers = ["Jean", "Beatriz"];
```
I thought it would be pretty easy but I guess I'm not familiar enough with javascript 😬
## My solution
After a bit of thinking, I came up with the following statement:
> I need to filter the skills based on which users are selected. So I need to loop over the `selectedUsers` array and filter the skills according to their `user` value.
After a bit more trials and errors, this is the code I ended up using in a `computed property`:
```javascript
// index.vue
const filteredSkills = selectedUsers.map((user) => {
return skills.filter((skill) => {
return skill.user === user;
});
});
```
I used `map()` in order to loop on the second array and used its string value to only include the corresponding skills with `filter()`.
I'm pretty sure there is a better way to do it though…

View file

@ -0,0 +1,189 @@
---
title: Buttons hover
subtitle: Simple, but nice.
lang: en
slug: "buttons"
excerpt: Easy to grab and use hover effects.
tags: ["CSS"]
code: true
createdAt: "2020-10-08T09:00:00.000Z"
---
## General rules
All the buttons use these styles as a “reset”:
> Don't forget to prefix if necessary!
```css
.btn {
margin: 20px 0;
padding: 12px 26px;
position: relative;
display: inline-block;
overflow: hidden;
font-size: 20rem; /* 20px */
line-height: 1.6;
text-align: center;
text-decoration: none;
font-weight: bold;
cursor: pointer;
border: none;
border-radius: 2px;
-moz-appearance: none;
-webkit-appearance: none;
color: white;
background-color: hotpink;
transition: background-color 0.3s ease;
}
```
## Add an icon
<button role="none" class="btn btn-icon">
<span>Icon</span>
</button>
```css
.btn-icon {
background-color: hotpink;
}
.btn-icon::before {
content: url("~assets/svg/arrow-right-white.svg");
position: absolute;
width: 20px;
top: 50%;
right: 0;
transform: translate(40px, -50%);
transition: transform ease 0.3s;
}
.btn-icon:hover,
.btn-icon:focus {
background-color: darkorchid;
}
.btn-icon:hover::before,
.btn-icon:focus::before {
transform: translate(-10px, -50%);
}
.btn-icon > span {
display: inline-block;
width: 100%;
height: 100%;
transition: transform 0.3s ease;
}
.btn-icon:hover > span,
.btn-icon:focus > span {
transform: translateX(-10px);
}
```
## Double shutter down
<button role="none" class="btn btn-rideau">
<span>Shutter</span>
</button>
```css
.btn-rideau {
border: 2px solid #10113a;
color: #10113a;
background-color: transparent;
transition: color 0.3s ease;
}
.btn-rideau:hover {
color: white;
}
.btn-rideau::before {
background: hotpink;
}
.btn-rideau::after {
background: darkorchid;
}
.btn-rideau::before,
.btn-rideau::after {
content: "";
position: absolute;
height: 100%;
width: 100%;
bottom: 100%;
left: 0;
z-index: -1;
transition: transform 0.3s;
transition-timing-function: ease;
transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1);
}
.btn-rideau:hover::before,
.btn-rideau:hover::after,
.btn-rideau:focus::before,
.btn-rideau:focus::after {
transform: translateY(100%);
}
.btn-rideau:hover::after,
.btn-rideau:focus::after {
transition-delay: 0.175s;
}
```
## Animated gradient
<button role="none" class="btn btn-gradient">
<span>Gradient</span>
</button>
```css
.btn-gradient {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
background-position: 0% 50%;
animation: GradientReverse 0.5s ease 1 normal forwards;
}
.btn-gradient:hover,
.btn-gradient:focus {
animation: Gradient 0.5s ease 1 normal forwards;
}
@keyframes Gradient {
0% {
background-position: 0% 50%;
}
100% {
background-position: 100% 100%;
}
}
@keyframes GradientReverse {
0% {
background-position: 100% 100%;
}
100% {
background-position: 0% 50%;
}
}
```
## Non destructive scale
<button role="none" class="btn btn-scale">
<span>Scale</span>
</button>
```css
.btn-scale {
overflow: visible;
color: #10113a;
background-color: transparent;
}
.btn-scale::after {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
border: 2px solid #10113a;
border-radius: 2px;
transition: transform 0.3s ease;
}
.btn-scale:hover::after,
.btn-scale:focus::after {
transform: scale(1.1);
}
```

View file

@ -0,0 +1,11 @@
---
title: Full width image
subtitle: Translation in progress, stay tuned ;)
lang: en
slug: "image-full"
createdAt: "2020-09-15T09:00:00.000Z"
updatedAt: "2022-06-08T14:24:06.000Z"
tags: ["CSS"]
---
[Go back to available snippets](/en/snippets/)

View file

@ -0,0 +1,139 @@
---
title: Static website and GraphQL queries with Nuxt.js
subtitle: Graphql client is king.
lang: en
slug: "nuxt-graphql-static"
createdAt: "2022-06-08T14:24:06.000Z"
updatedAt: "2022-09-08T13:43:33.000Z"
excerpt: When the most used gql module doesn't work…
tags: ["nuxt.js"]
---
## The problem
I encountered a nasty bug while using static generation with Nuxt and [nuxt apollo](https://github.com/nuxt-community/apollo-module "Dépôt github du module nuxt apollo (new tab)") client.
I found [the issue](https://github.com/nuxt-community/apollo-module/issues/339 "Github issue on nuxt/apollo repository (new tab)") already reported on github.
It seems the module doesn't handle static generation correctly with `nuxt generate`.
I could find request to my local API url after the static generation. Moreover, it also seemed like `<nuxt-link>` navigation was broken.
## The solution 🙌
Fortunately, there is another Nuxt module that handles GraphQL requests!
[Nuxt graphql request to the rescue!](https://github.com/gomah/nuxt-graphql-request)
### The conf
```javascript
// nuxt.config.js
buildModules: [
'nuxt-graphql-request',
],
graphql: {
clients: {
default: {
endpoint: 'http://API_URL/graphql',
options: {
headers: {
authorization: 'Bearer API_TOKEN',
},
},
},
},
},
```
### The request
The best approach so far is to use `asyncData` in pages and `fetch` in components. Using `fetch` in pages does not work well at all with `nuxt generate`.
I also install the `graphql-tag` package (only in `devDependencies`) to be able to import directly `.gql` files.
Query example:
```graphql
# homepage.gql
query {
homepage {
title
subtitle
hero {
id
alt
}
}
}
```
#### Inside a page
```javascript
// index.vue
<script>
import homepageQuery from '~/graphql/queries/singles/homepage'
export default {
async asyncData({ $graphql }) {
const data = await $graphql.default.request(homepageQuery)
return { data }
},
}
</script>
```
#### Inside a component
It is safer to wait until `fetch` has received a response before displaying anything. You can use `$fetchState` to be sure ([documentation](https://nuxtjs.org/docs/2.x/components-glossary/pages-fetch "Documentation on the fetch hook (new tab)")).
```javascript
// Header.vue
<template>
<header v-if="!$fetchState.pending">
</header>
</template>
<script>
import headerQuery from '~/graphql/queries/singles/header'
export default {
data() {
return {
data: {},
}
},
async fetch() {
try {
const data = await this.$graphql.default.request(headerQuery)
this.data = data
} catch (error) {
console.error(JSON.stringify(error, undefined, 2))
}
},
}
</script>
```
### Options
To pass options to the request, for example for a multilingual version with [nuxt/i18n](https://i18n.nuxtjs.org/) and/or a url parameter in a dynamic page:
```javascript
// _slug.vue
<script>
import articleQuery from '~/graphql/queries/articles'
export default {
async asyncData({ $graphql, app, params }) {
const locale = app.i18n.localeProperties.iso
const data = await $graphql.default.request(articleQuery, {
code: locale,
slug: params.slug,
})
return { data }
},
}
</script>
```

View file

@ -0,0 +1,74 @@
---
title: The best cookies
subtitle: Consentless biscuits.
lang: en
slug: "super-cookies"
createdAt: "2022-06-08T14:24:06.000Z"
excerpt: It's a real recipe, not a joke about annoying files.
tags: ["food"]
---
## Vegetalian version
### Ingredients
- 250 grams of flour
- 70 grams of muscovado/vergeoise sugar (unrefined)
- 20 grams of brown sugar
- 1 pinch of salt
- 1 tablespoon of baking powder
- 3/4 of aquafaba from 400g of chickpea (chickpea water)
- 125 grams of coconut oil
- 2 teaspoons of maple syrup
- 1 chocolate bar (black) cut in “&nbsp;chunks&nbsp;
### Method
- if necessary, melt the coconut oil over low heat
- meanwhile, mix all the dry ingredients
- add all liquid ingredients (oil, aquafaba, maple syrup)
- mix well
- add the chocolate
- mix well (fig. 1)
### Baking
Form balls with the obtained mixture on a baking sheet.
Bake for 9 minutes at 210 degrees (Celsius) - fan setting (fig. 2).
## Non vegetalian version
### Ingredients
- 250 grams of flour
- 70 grams of muscovado/vergeoise sugar (unrefined)
- 20 grams of brown sugar
- 1 pinch of salt
- 1 table spoon of baking powder
- 1 egg
- 125 grams of melted butter
- 2 teaspoons of honey
- 1 chocolate bar (black) cut in “&nbsp;chunks&nbsp;
### Method
- melt butter over low heat
- meanwhile, mix all dry ingredients
- add all liquid ingredients (melted butter, egg, honey)
- mix well
- add the chocolate
- mix well (fig. 1)
### Baking
Form balls with the obtained mixture on a baking sheet.
Bake for 9 minutes at 210 degrees (Celsius) - fan setting (fig. 2).
## Notes
Chocolate can be replaced by anything like nuts, raisins, legos... (don't eat legos be reasonable).
## Figures
![Fig.1 - All ingredients mixed together to form a brown paste.](https://assets.nardu.in/cookies-fig-1.jpg)
![Fig.2 - Baked cookies are very soft.](https://assets.nardu.in/cookies-fig-2.jpg)

View file

@ -0,0 +1,68 @@
---
title: Toulouse yourself
subtitle: Only the bestest
lang: en
slug: "toulouse-fun"
excerpt: Gonna have to trust me on this ¯\_(ツ)_/¯
tags: ["lifestyle"]
createdAt: "2022-06-22T15:34:45.000Z"
---
Here is my list of great places to go to when in Toulouse. There are of course a lot of other great places to go to, these are just my all time favourite.
**It's always a good idea to make a reservation!**
## Restaurants
### French cuisine
- [Solides](https://www.solides.fr/) — semi-gastronomic
- [Les impulsifs](https://les-impulsifs-toulouse.eatbu.com/?lang=en) — semi-gastronomic
- [Sixta](https://sixta-toulouse.fr/) — vege/vegan/gluten friendly
- [Attila](https://attila.site-solocal.com/) — great **fish restaurant,** just above the Victor Hugo market
- [Chez Emile](https://www.restaurant-emile.com/) - best [cassoulet](https://en.wikipedia.org/wiki/Cassoulet) in town (or so I'm told)
### Korean
- [Le ptit Louis](https://leptitlouis.fr/) — best of its kind, **only for lunch**
- [Kongbap](https://kong-bap.com/) — street-food like
### Japanese
- [Iori](https://www.iori.fr/) — best ramen
- [Japoyaki](https://www.qwant.com/maps/place/osm:node:2447719414@Japoyaki#map=16.50/43.6061725/1.4473402) — best sushi/sashimis
## Drinks and snacks
### Bars
- [Le Bièrographe](https://www.qwant.com/maps/place/osm:node:1532531236@Le_Bi%C3%A8rographe#map=16.50/43.5986892/1.4428327) — all time favourite, **check out the typical toulouse basement**
- [A Taula](https://www.facebook.com/ataulatolosa/) — all time favourite in summer, **amazing terrace,** also: great tapas
- [The Hopscotch Pub](https://www.qwant.com/maps/place/osm:node:5592180378@The_Hopscotch#map=18.14/43.6006796/1.4431385) — good beers, good whiskies, good cocktials, good food
### Cafés & tea rooms
- [Bapz](https://www.bapz.fr/contact) — Excellent pastries / hot beverages
- [Ô thé divin](https://fr-fr.facebook.com/%C3%94-Th%C3%A9-Divin-245018828864405/) — nice lunch options
- [Les Rêveries dHercule](https://www.lesreveriesdhercule.com/) — Pottery Café, relaxing activity (ceramics need to be baked, there'll be a delay to get them back)
- Bonus: the best bakeries in [Carmes](https://www.qwant.com/maps/place/osm:node:450165912@Boulangerie_des_Carmes#map=16.37/43.6022638/1.4439872) and [Saint-Aubin](https://www.qwant.com/maps/place/osm:node:456844404@La_P%C3%A9trie#map=18.84/43.6045088/1.4544694) — croissants, baguettes **traditions**, chocolatines and more
### Wine shops
- [l'envie du sud](https://www.qwant.com/maps/place/osm:node:3861692629@LEnvie#map=19.57/43.5978194/1.4443930) — amazing selection of wines and other spirits, excellent advice from the staff
- [enoteca](https://www.qwant.com/maps/place/osm:node:3751077562@Enoteca_31#map=16.50/43.6045636/1.4531952) — smaller selection but more beers and great advice from the staff as well
## Other delights
### Ice creams
- [Forno gusto](https://www.qwant.com/maps/place/osm:node:2462248749@Caf%C3%A9t%C3%A9ria_Gelateria#map=20.00/43.6027626/1.4421450) — only in the summer
- [Moustache](https://www.qwant.com/maps/place/osm:node:2165543146@Glaces_Moustache#map=16.50/43.6036985/1.4350540) — lots of flavours
### Cheese shop
- [Xavier](https://xavier.fr/) — one of the **best of the country**, two shops in Toulouse, including one at Victor Hugo market
- [Massembea](https://www.qwant.com/maps/place/osm:node:6164095797@Massembea#map=16.50/43.6043930/1.4539490) — a serious contender in Toulouse (weird hours)
### Delicatessen
- [Café Bacquié](http://cafe-bacquie.com/) — stock up on fine foods, coffees, teas and other great quality products