Browse Source

feat: init

restructure
Garrit Franke 4 years ago
parent
commit
9240fcdd19
  1. 36
      components/BlogList.js
  2. 48
      components/Header.js
  3. 35
      components/Layout.js
  4. 223
      components/Meta.js
  5. 9
      next.config.js
  6. 341
      package-lock.json
  7. 6
      package.json
  8. 6
      pages/_app.js
  9. 108
      pages/index.js
  10. 54
      pages/posts/[post].js
  11. 14
      pages/posts/index.js
  12. 81
      posts/fighting-array-functions-with-es6.md
  13. 83
      posts/lightweight-vpn-with-wireguard.md
  14. 63
      posts/patch-based-git-workflow.md
  15. 28
      posts/quick-tip-terminal-pastebin.md
  16. 120
      posts/testing-isnt-hard.md
  17. 40
      posts/whom-do-you-trust.md

36
components/BlogList.js

@ -0,0 +1,36 @@
import Link from "next/link";
const BlogList = ({ posts }) => {
console.log(posts);
const blogElements = posts
.sort((a, b) => a.frontmatter.date < b.frontmatter.date)
.map((post) => (
<div>
<Link href={"/posts/" + post.slug}>
<a>{post.frontmatter.title}</a>
</Link>
<style jsx>
{`
a {
margin-top: 1em;
}
`}
</style>
</div>
));
return (
<div>
{blogElements}
<style jsx>
{`
div {
width: 100%;
height: 100vh;
}
`}
</style>
</div>
);
};
export default BlogList;

48
components/Header.js

@ -0,0 +1,48 @@
import Link from "next/link";
export default function Header(props) {
return (
<header className="header">
<nav className="nav" role="navigation" aria-label="main navigation">
<Link href="/">
<h1>{props.siteTitle}</h1>
</Link>
</nav>
<style jsx>
{`
h1 {
margin-bottom: 0;
}
h1:hover {
cursor: pointer;
}
nav {
padding: 1.5rem 1.25rem;
border-bottom: 1px solid #ebebeb;
display: flex;
justify-content: space-between;
flex-direction: row;
align-items: center;
}
@media (min-width: 768px) {
.header {
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
.nav {
padding: 2rem;
width: 30vw;
height: 100%;
border-right: 1px solid #ebebeb;
border-bottom: none;
flex-direction: column;
align-items: flex-start;
}
}
`}
</style>
</header>
);
}

35
components/Layout.js

@ -0,0 +1,35 @@
import Header from "./Header";
import Meta from "./Meta";
export default function Layout({ siteTitle, siteDescription, children }) {
return (
<section className="layout">
<Meta siteTitle={siteTitle} description={siteDescription} />
<Header siteTitle={siteTitle} />
<div className="content">{children}</div>
<style jsx>
{`
.layout {
overflow-x: hidden;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.content {
flex-grow: 1;
}
@media (min-width: 768px) {
.layout {
display: block;
}
.content {
flex-grow: none;
width: 70vw;
margin-left: 30vw;
}
}
`}
</style>
</section>
);
}

223
components/Meta.js

@ -0,0 +1,223 @@
import Head from "next/head";
export default function Meta(props) {
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
<title>{props.siteTitle}</title>
<meta name="Description" content={props.description}></meta>
</Head>
<style jsx global>
{`
@import url("https://fonts.googleapis.com/css?family=Work+Sans&display=swap");
* {
box-sizing: inherit;
}
html {
box-sizing: border-box;
overflow-y: scroll;
}
body {
margin: 0;
font-family: "Work Sans", "Helvetica Neue", Helvetica, sans-serif;
overflow-x: hidden;
color: #000;
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
text-decoration: none;
color: inherit;
transition: opacity 0.2s ease;
}
a:hover {
transition: opacity 0.2s ease;
opacity: 0.5;
text-decoration-color: inherit;
}
ul {
list-style: none;
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ol {
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ul,
ol,
p {
margin-bottom: 1.45rem;
}
img {
max-width: 100%;
}
img,
figure,
table,
fieldset {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
pre {
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 1.45rem;
font-size: 0.85rem;
line-height: 1.42;
background: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
overflow: auto;
word-wrap: normal;
padding: 1.45rem;
}
table {
font-size: 1rem;
line-height: 1.45rem;
border-collapse: collapse;
width: 100%;
}
blockquote {
margin-left: 1.45rem;
margin-right: 1.45rem;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
strong {
font-weight: bold;
}
li {
margin-bottom: calc(1.45rem / 2);
}
ol li {
padding-left: 0;
}
ul li {
padding-left: 0;
}
li > ol {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
li > ul {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
blockquote *:last-child {
margin-bottom: 0;
}
li *:last-child {
margin-bottom: 0;
}
p *:last-child {
margin-bottom: 0;
}
li > p {
margin-bottom: calc(1.45rem / 2);
}
code {
font-size: 0.85rem;
line-height: 1.45rem;
}
{
/* //TYPOGRAPHY------------------------------------- */
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-family: "Work Sans", "Helvetica Neue", Helvetica, sans-serif;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
text-rendering: optimizeLegibility;
}
h1,
h2 {
font-weight: 500;
}
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.7rem;
letter-spacing: -0.75px;
line-height: 1.2;
}
h3 {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.5;
color: #464646;
}
@media (min-width: 1280px) {
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.5rem;
letter-spacing: -0.75px;
line-height: 1.1667;
}
h3 {
font-size: 1rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
line-height: 1.4375;
}
}
`}
</style>
</>
);
}

9
next.config.js

@ -0,0 +1,9 @@
module.exports = {
webpack: function (config) {
config.module.rules.push({
test: /\.md$/,
use: "raw-loader",
});
return config;
},
};

341
package-lock.json generated

@ -1533,6 +1533,14 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"arity-n": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
@ -1631,6 +1639,11 @@
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz",
"integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA=="
},
"bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
"integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -1973,6 +1986,21 @@
}
}
},
"character-entities": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="
},
"character-entities-legacy": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
},
"character-reference-invalid": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="
},
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@ -2055,6 +2083,11 @@
"shallow-clone": "^3.0.0"
}
},
"collapse-white-space": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
"integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ=="
},
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -2650,6 +2683,11 @@
"estraverse": "^4.1.1"
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@ -2754,6 +2792,11 @@
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extend-shallow": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
@ -3015,6 +3058,17 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"gray-matter": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.2.tgz",
"integrity": "sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw==",
"requires": {
"js-yaml": "^3.11.0",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -3113,6 +3167,17 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
"html-to-react": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.4.3.tgz",
"integrity": "sha512-txe09A3vxW8yEZGJXJ1is5gGDfBEVACmZDSgwDyH5EsfRdOubBwBCg63ZThZP0xBn0UE4FyvMXZXmohusCxDcg==",
"requires": {
"domhandler": "^3.0",
"htmlparser2": "^4.1.0",
"lodash.camelcase": "^4.3.0",
"ramda": "^0.27"
}
},
"htmlparser2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
@ -3216,6 +3281,20 @@
}
}
},
"is-alphabetical": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="
},
"is-alphanumerical": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
"requires": {
"is-alphabetical": "^1.0.0",
"is-decimal": "^1.0.0"
}
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
@ -3257,6 +3336,11 @@
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
},
"is-decimal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="
},
"is-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
@ -3292,6 +3376,11 @@
"is-extglob": "^2.1.1"
}
},
"is-hexadecimal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="
},
"is-negative-zero": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
@ -3315,6 +3404,11 @@
}
}
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
},
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@ -3339,11 +3433,21 @@
"has-symbols": "^1.0.1"
}
},
"is-whitespace-character": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
"integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w=="
},
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
},
"is-word-character": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
"integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA=="
},
"is-wsl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
@ -3373,6 +3477,15 @@
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-yaml": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
"integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@ -3442,6 +3555,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@ -3491,6 +3609,11 @@
"object-visit": "^1.0.0"
}
},
"markdown-escapes": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
"integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -3501,6 +3624,14 @@
"safe-buffer": "^5.1.2"
}
},
"mdast-add-list-metadata": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz",
"integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==",
"requires": {
"unist-util-visit-parents": "1.1.2"
}
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@ -4024,6 +4155,19 @@
"safe-buffer": "^5.1.1"
}
},
"parse-entities": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
"integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
"requires": {
"character-entities": "^1.0.0",
"character-entities-legacy": "^1.0.0",
"character-reference-invalid": "^1.0.0",
"is-alphanumerical": "^1.0.0",
"is-decimal": "^1.0.0",
"is-hexadecimal": "^1.0.0"
}
},
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@ -4269,6 +4413,11 @@
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
},
"ramda": {
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
"integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -4286,6 +4435,15 @@
"safe-buffer": "^5.1.0"
}
},
"raw-loader": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.1.tgz",
"integrity": "sha512-baolhQBSi3iNh1cglJjA0mYzga+wePk7vdEX//1dTFd+v4TsQlQE0jitJSNF1OIP82rdYulH7otaVmdlDaJ64A==",
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^2.6.5"
}
},
"react": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
@ -4312,6 +4470,21 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-markdown": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz",
"integrity": "sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw==",
"requires": {
"html-to-react": "^1.3.4",
"mdast-add-list-metadata": "1.0.1",
"prop-types": "^15.7.2",
"react-is": "^16.8.6",
"remark-parse": "^5.0.0",
"unified": "^6.1.5",
"unist-util-visit": "^1.3.0",
"xtend": "^4.0.1"
}
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@ -4414,6 +4587,28 @@
}
}
},
"remark-parse": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz",
"integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==",
"requires": {
"collapse-white-space": "^1.0.2",
"is-alphabetical": "^1.0.0",
"is-decimal": "^1.0.0",
"is-whitespace-character": "^1.0.0",
"is-word-character": "^1.0.0",
"markdown-escapes": "^1.0.0",
"parse-entities": "^1.1.0",
"repeat-string": "^1.5.4",
"state-toggle": "^1.0.0",
"trim": "0.0.1",
"trim-trailing-lines": "^1.0.0",
"unherit": "^1.0.4",
"unist-util-remove-position": "^1.0.0",
"vfile-location": "^2.0.0",
"xtend": "^4.0.1"
}
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@ -4429,6 +4624,11 @@
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"replace-ext": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
"integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs="
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
@ -4618,6 +4818,25 @@
"ajv-keywords": "^3.4.1"
}
},
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"requires": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -4838,6 +5057,11 @@
"extend-shallow": "^3.0.0"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"ssri": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz",
@ -4855,6 +5079,11 @@
"type-fest": "^0.7.1"
}
},
"state-toggle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
"integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ=="
},
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@ -5000,6 +5229,11 @@
"ansi-regex": "^5.0.0"
}
},
"strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI="
},
"style-loader": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz",
@ -5303,6 +5537,21 @@
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
"integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="
},
"trim": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
"integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0="
},
"trim-trailing-lines": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
"integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA=="
},
"trough": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA=="
},
"ts-pnp": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
@ -5333,6 +5582,15 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"unherit": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
"integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
"requires": {
"inherits": "^2.0.0",
"xtend": "^4.0.0"
}
},
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@ -5357,6 +5615,19 @@
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg=="
},
"unified": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
"integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
"requires": {
"bail": "^1.0.0",
"extend": "^3.0.0",
"is-plain-obj": "^1.1.0",
"trough": "^1.0.0",
"vfile": "^2.0.0",
"x-is-string": "^0.1.0"
}
},
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@ -5389,6 +5660,47 @@
"imurmurhash": "^0.1.4"
}
},
"unist-util-is": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
"integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A=="
},
"unist-util-remove-position": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
"integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
"requires": {
"unist-util-visit": "^1.1.0"
}
},
"unist-util-stringify-position": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
"integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ=="
},
"unist-util-visit": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
"integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
"requires": {
"unist-util-visit-parents": "^2.0.0"
},
"dependencies": {
"unist-util-visit-parents": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
"integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
"requires": {
"unist-util-is": "^3.0.0"
}
}
}
},
"unist-util-visit-parents": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz",
"integrity": "sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q=="
},
"unset-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
@ -5492,6 +5804,30 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"vfile": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
"integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
"requires": {
"is-buffer": "^1.1.4",
"replace-ext": "1.0.0",
"unist-util-stringify-position": "^1.0.0",
"vfile-message": "^1.0.0"
}
},
"vfile-location": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
"integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA=="
},
"vfile-message": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
"integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
"requires": {
"unist-util-stringify-position": "^1.1.1"
}
},
"vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
@ -5726,6 +6062,11 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"x-is-string": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

6
package.json

@ -8,8 +8,12 @@
"start": "next start"
},
"dependencies": {
"glob": "^7.1.6",
"gray-matter": "^4.0.2",
"next": "9.5.3",
"raw-loader": "^4.0.1",
"react": "16.13.1",
"react-dom": "16.13.1"
"react-dom": "16.13.1",
"react-markdown": "^4.3.1"
}
}

6
pages/_app.js

@ -1,7 +1,7 @@
import '../styles/globals.css'
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
return <Component {...pageProps} />;
}
export default MyApp
export default MyApp;

108
pages/index.js

@ -1,65 +1,49 @@
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import Layout from "../components/Layout";
import BlogList from "../components/BlogList";
import matter from "gray-matter";
export default function Home() {
const Index = (props) => {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>
<p className={styles.description}>
Get started by editing{' '}
<code className={styles.code}>pages/index.js</code>
</p>
<div className={styles.grid}>
<a href="https://nextjs.org/docs" className={styles.card}>
<h3>Documentation &rarr;</h3>
<p>Find in-depth information about Next.js features and API.</p>
</a>
<a href="https://nextjs.org/learn" className={styles.card}>
<h3>Learn &rarr;</h3>
<p>Learn about Next.js in an interactive course with quizzes!</p>
</a>
<a
href="https://github.com/vercel/next.js/tree/master/examples"
className={styles.card}
>
<h3>Examples &rarr;</h3>
<p>Discover and deploy boilerplate example Next.js projects.</p>
</a>
<a
href="https://vercel.com/import?filter=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
>
<h3>Deploy &rarr;</h3>
<p>
Instantly deploy your Next.js site to a public URL with Vercel.
</p>
</a>
</div>
</main>
<footer className={styles.footer}>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{' '}
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
</a>
</footer>
</div>
)
<Layout pathname="/" siteTitle="/dev.space" siteDescription="">
<section>
<BlogList posts={props.posts} />
</section>
</Layout>
);
};
export async function getStaticProps() {
//get posts & context from folder
const posts = ((context) => {
const keys = context.keys();
const values = keys.map(context);
const data = keys.map((key, index) => {
// Create slug from filename
const slug = key
.replace(/^.*[\\\/]/, "")
.split(".")
.slice(0, -1)
.join(".");
const value = values[index];
// Parse yaml metadata & markdownbody in document
const document = matter(value.default);
return {
frontmatter: document.data,
markdownBody: document.content,
slug,
};
});
return data;
})(require.context("../posts", true, /\.md$/));
return {
props: {
posts,
title: "/dev.space",
description: "",
},
};
}
export default Index;

54
pages/posts/[post].js

@ -0,0 +1,54 @@
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";
import Layout from "../../components/Layout";
import glob from "glob";
import { useRouter } from "next/router";
export default function BlogTemplate(props) {
const router = useRouter();
const { post } = router.query;
console.log(props.paths);
// Render data from `getStaticProps`
return (
<Layout siteTitle={props.siteTitle}>
<article>
<h1>{props.frontmatter.title}</h1>
<div>
<ReactMarkdown source={props.markdownBody} />
</div>
</article>
</Layout>
);
}
export async function getStaticProps({ ...ctx }) {
const { post } = ctx.params;
const content = await import(`../../posts/${post}.md`);
const data = matter(content.default);
return {
props: {
siteTitle: "/dev.space",
frontmatter: data.data,
markdownBody: data.content,
},
};
}
export async function getStaticPaths() {
//get all .md files in the posts dir
const blogs = glob.sync("posts/**/*.md");
//remove path and extension to leave filename only
const blogSlugs = blogs.map((file) =>
file.split("/")[1].replace(/ /g, "-").slice(0, -3).trim()
);
// create paths with `slug` param
const paths = blogSlugs.map((slug) => `/posts/${slug}`);
return {
paths,
fallback: false,
};
}

14
pages/posts/index.js

@ -0,0 +1,14 @@
import Layout from "../../components/Layout";
import BlogList from "../../components/BlogList";
const Index = (props) => {
return (
<Layout pathname="/" siteTitle="/dev.space" siteDescription="">
<section>
<BlogList />
</section>
</Layout>
);
};
export default Index;

81
posts/fighting-array-functions-with-es6.md

@ -0,0 +1,81 @@
---
title: Fighting Array Functions with ES6
date: "2019-04-07"
---
Yesterday, I came across an interesting bug regarding JavaScript Arrays, and I wanted to share my approach to fixing it.
At a basic level, I wanted to pass part of an array to a function, but wanted to use the original array later on.
```js
let arr = [1, 2, 3, 4, 5]
let something = arr.splice(0, 3)
do(something) // []
DoSomethingWithOriginal(arr)
```
Thinking that Array.prototype functions don’t mutate the array directly, I moved on with my day. This lead to a bunch of problems down the line.
Some array methods in the EcmaScript specification are designed to mutate arrays, while others do not.
### Non-mutating functions
- Array.prototype.map()
- Array.prototype.slice()
- Array.prototype.join()
- …
These functions do not mutate the array they are called on. For example:
```js
let arr = [1, 2, 3, 4, 5];
let partOfArr = arr.slice(1, 2);
console.log(partOfArr); // [2, 3]
console.log(arr); // [1, 2, 3, 4, 5]
```
### Mutating functions
- Array.prototype.sort()
- Array.prototype.splice()
- Array.prototype.reverse()
- …
These methods mutate the array directly. This can lead to unreadable code, as the value can be manipulated from anywhere. For example:
```js
let arr = [5, 2, 4];
arr.sort();
console.log(arr); // [2, 4, 5]
```
To me, it is very unclear, which functions do, and which don’t mutate arrays directly. But, there’s a simple trick you can use to stop letting the functions mutate arrays directly, ultimately leading to more readable and reliable code.
## Enter: The ES6 Spread Operator!
![Spread Operator](https://images.unsplash.com/photo-1518297056586-889f796873e0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1225&q=80)
Take a look at this snippet:
```js
let arr = [3, 5, 1, 2, 4];
let sorted = [...arr].sort();
console.log(arr); // [3, 5, 1, 2, 4]
console.log(sorted); // [1, 2, 3, 4, 5]
```
Voilà! We have a sorted array, and the original one is also around. The spread operator(`[...arr]`) is used to create a new array with every value of arr .
You can use this for arrays, as well as objects:
```js
let obj = {
field: "example",
};
let extendedObj = {
...obj,
anotherField: 42,
};
console.log(extendedObj.field); // "example"
```
## Conclusion
ES6 brought us awesome features like let and const assignments, as well as arrow functions. A more unknown feature however is the spread operator. I hope you now know how to use the spread operator, and that you can adopt it for cleaner and simpler code.

83
posts/lightweight-vpn-with-wireguard.md

@ -0,0 +1,83 @@
---
title: Quick Tip! Setting up a lightweight Server-Client VPN with wireguard
date: "2020-08-19"
---
This blog post has been taken over from my [collection of "Today I Learned" articles](https://garrit.xyz/til).
You can easily set up a private network of your devices. This way you can "talk" to your phone, raspberry pi etc. over an **encrypted** network, with simple IP-addresses.
![](https://images.unsplash.com/photo-1505659903052-f379347d056f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2550&q=80)
Firstly, install wireguard on all of your systems. Simply install the `wireguard` package from your package manager respectively. Check out [the official installation guide](https://www.wireguard.com/install/) if you can't find the package. If you're on debian, try [this](https://wiki.debian.org/WireGuard?action=show&redirect=Wireguard) guide. There's also an app for Android, iOS and MacOS.
Every participent (Client and server) needs a key-pair. To generate this, run this command first on the server, and on all clients:
```bash
wg genkey | tee wg-private.key | wg pubkey > wg-public.key
```
It might make sense to do this as root. This way you don't have to type `sudo` with every command.
## Server Configuration
You will need to create a configuration for the server. Save this template at `/etc/wireguard/wg0.conf`, and replace the fields where needed:
```conf
[Interface]
PrivateKey = <Server private key from wg-private.key>
Address = 10.0.0.1/24 # IP Address of the server. Using this IP Address, you can assign IPs ranging from 10.0.0.2 - 10.0.0.254 to your clients
ListenPort = 51820 # This is the standard port for wireguard
# The following fields will take care of routing
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Laptop
[Peer]
PublicKey = <Public Key of Laptop Client>
AllowedIPs = 10.0.0.2/32 # The client will be reachable at this address
# Android Phone
[Peer]
PublicKey = <Public Key of Phone Client>
AllowedIPs = 10.0.0.3/32
# ...
```
Then run `wg-quick up wg0` to start the wireguard interface with the configuration from `/etc/wireguard/wg0`.
## Setting up clients
Setting up clients is very similar to the server setup process. Generate a keypair on each client, save the following config to `/etc/wireguard/wg0.conf` and replace the nessessary fields:
```conf
[Interface]
PrivateKey = <Client Private Key from wg-private.key>
Address = 10.0.0.2/32 # The fixed address of the client. Needs to be specified in the server config as well
[Peer]
PublicKey = <Server Public key>
AllowedIPs = 10.0.0.0/24 # Routes all traffic in this subnet to the server. If you want to tunnel all traffic through the wireguard connection, use 0.0.0.0/0 here instead
Endpoint = <Public Server IP>:51820
PersistentKeepalive = 25 # Optional. Will ping the server every 25 seconds to remain connected.
```
On every client, run `wg-quick up wg0` to start the interface using the config at `/etc/wireguard/wg0.conf`.
This whole proccess might be easier on GUIs like Android or MacOS.
Now, try to ping your phone from your laptop:
```
ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=5382 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=4364 ms
```
### References
- [Official Documentation](https://www.wireguard.com/)
- [https://www.stavros.io/posts/how-to-configure-wireguard/](https://www.stavros.io/posts/how-to-configure-wireguard/)

63
posts/patch-based-git-workflow.md

@ -0,0 +1,63 @@
---
title: The Patch-Based Git Workflow
date: "2020-09-28"
---
If you have ever contributed to an open source project, chances are you have opened a pull request on GitHub or a similar platform to present your code to the maintainers. While this is a very approachable way of getting your code reviewed, some projects have decided against using pull requests and instead accept patches via email.
## An introduction to patches
A patch is essentially a git commit expressed in plain text. It describes what commit the change is based on, and what has changed. A basic patch looks like this:
```
From 92132241233033a123c4fa833449d6a0d550219c Mon Sep 17 00:00:00 2001
From: Bob <bob@example.com>
Date: Tue, 25 May 2009 15:42:16 +0200
Subject: [PATCH 1/2] first change
---
test.txt | 1 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/test.txt b/test.txt
index 7634da4..270eb95 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-Hallo Bob
+Hallo Alice!
```
As you can see, it is very readable for both the reviewer and the machine.
## Sending and receiving patches
The easiest way you can generate a patch from a commit is to use `git-format-patch`:
```
git format-patch HEAD^
```
This will generate a `.patch` file, that can be embedded into an email and sent to the maintainers. Oftentimes they will then reply to your mail with some inline comments about your code.
To simplify this process further, git has the `send-email` command, which let's you send the patch directly to someone without needing to embed it manually. I won't go into details about this, but there is a [well written guide](https://git-send-email.io/) on how to set it up.
If you have received a patch from someone, you can apply it to your tree with the `am` (apply mail) command:
```
git am < 0001-first-change.patch
```
check your `git log` to see the patch in form of the latest commit.
## Why even bother
You might think that this is just a silly and outdated approach to collaborative development. "Why not simply open a pull request?" you might ask. Some projects, especially low-level oriented ones like the Linux kernel, do not want to rely on third-party platforms like GitHub to host their code, with good reasons:
1. Everyone can participate! You don't need to register an account on some proprietary website to collaborate in a project that uses a patch-based workflow. You don't even have to expose your identity, if you don't want to. All you need is an email-address, and frankly most of us have one.
2. It's plain simple! Once you get used to generating and applying patches on the command line, it is in fact easier and faster than opening a pull request in some clunky GUI. It doesn't get simpler than plain text.
3. It is rewarding! Once you have submitted a patch to a project, there is no better feeling than getting a simple "Applied, thanks!" response from a maintainer. And if it's a response that contains feedback rather than an approval, it feels even better to submit that reworked code again and get it eventually applied.
## Conclusion
The patch-based workflow is an alternative way to collaborate with developers. If it helps you in your day to day business depends on the projects you are contributing to, but in the end it is always good to have many tools under your belt.

28
posts/quick-tip-terminal-pastebin.md

@ -0,0 +1,28 @@
---
title: Quick Tip! Sharing terminal output with Termbin
date: "2019-12-31"
---
Ever find yourself in a situation where you simply want to save or share the output of a terminal command? Selecting, copying and pasting text from stdout always feels quite tedious, if you just want to share the contents of a file.
A project called [Termbin](https://termbin.com/) tries to simplify this process. Just pipe the command you want to save to the following url on port `9999`, using Netcat:
```sh
echo "Hello, Blog!" | nc termbin.com 9999
```
Instead of showing the output, it will be forwarded to Termbin and show the URL, under which your output will be available:
```sh
➜ blog git:(master) ✗ cat ./some_file.txt | nc termbin.com 9999
https://termbin.com/faos
➜ blog git:(master) ✗
```
Sure enough, after navigating to [`https://termbin.com/faos`](https://termbin.com/faos), we will see the contents of `some_file.txt`. Neat!
### ⚠Word of Caution⚠
Do not pipe any personal information, credentials or any other private data into termbin. It will be instantly available to the general public, and theres no quick way to remove it.
Happy Pasting!✨

120
posts/testing-isnt-hard.md

@ -0,0 +1,120 @@
---
title: Testing isn't hard
date: "2019-11-08"
---
"I write two tests before implementing a method", "My project has 90% coverage".
I don't know about you, but that's something I don't hear very often. But why is that?
Testing is not even that difficult to do, but yet it is always coming short in my projects. About a year ago, I've tried to implement tests in my React applications with little success, mostly because integrating `enzyme` and configuring it correctly is not that intuitive as a relatively new developer. I want to share my (partly opinionated) approach to JavaScript testing with `jest`, to get you started. In a later post I will demonstrate a way to implement `enzyme` into your React projects.
# The basics of testing JavaScript functions
To get started, you need a npm-project. I don't think I have to explain that, but just in case:
```bash
mkdir awesome-testing-project
cd awesome-testing-project
npm init -y
```
Of course, we need a unit we want to test. What about a method that returns the first element of an array?
```js
module.exports = function firstElement(arr) {
return arr[1];
};
```
You already spotted a bug, huh? Let's keep it simple for now.
Install and initialize Jest, an open-source testing framework maintained by Facebook. When initializing, you should check every question with `y`.
```bash
npm i --save-dev jest
npx jest --init
```
Next up, we need to define our first test. Conventionally, we create a folder named `__tests__` in the directory of the module we want to test. inside it, there should be a file named `<module>.test.js`. Something like this:
```bash
▶ tree
.
├── package.json
└── src
├── __tests__
   └── firstElement.test.js
└── firstElement.js
```
Jest provides global functions that do not need to be imported in a file. A simple test can look like this:
```js
const firstElement = require("../firstElement.js");
test("firstElement gets first element of array", () => {
expect(firstElement([1, 2])).toBe(1);
});
```
`expect` is another word for `assert`. If you ask me, "Expect firstElement of [1, 2] to be 1" sounds reasonably english, doesn't it? After defining the test, all there is to do left is to run the `npm test` command, which has been created for us by running `npx jest --init` earlier.
```bash
▶ npm test
> jest
FAIL src/__tests__/firstElement.test.js
✕ firstElement (6ms)
● firstElement
expect(received).toBe(expected) // Object.is equality
Expected: 1
Received: 2
2 |
3 | test('firstElement', () => {
> 4 | expect(firstElement([1, 2])).toBe(1);
| ^
5 | });
6 |
at Object.<anonymous>.test (src/__tests__/firstElement.test.js:4:32)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.1s
Ran all test suites.
npm ERR! Test failed. See above for more details.
```
Whoops! Looks like we have found a bug! Let's fix it by adjusting the index of the return value in the firstElement function:
```js
module.exports = function firstElement(arr) {
return arr[0];
};
```
And after rerunning `npm test`:
```bash
▶ npm test
> jest
PASS src/__tests__/firstElement.test.js
✓ firstElement (4ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.666s, estimated 2s
Ran all test suites.
```
Yay, your first unit test! Of course, there is much more to find out about the Jest framework. To see a full guide, read the [official docs](https://jestjs.io/).
I have prepared a [template repository](https://github.com/garritfra/react-parcel-boilerplate) for building react apps. It also uses Jest to run tests, you don't have to worry about a thing! If you found this interesting, consider checking out my other blog posts, and/or check out my [GitHub](https://github.com/garritfra)!

40
posts/whom-do-you-trust.md

@ -0,0 +1,40 @@
---
title: Whom do you trust?
date: "2020-03-17"
---
Nowadays, password managers are a necessity if you care even the slightest about your personal belongings on the interwebs. But think about it, do you really want to trust another company to store your most sensitive information?
![](https://images.unsplash.com/photo-1522251670181-320150ad6dab?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2566&q=80)
##### TL;DR
Use a **stateless** password manager like [LessPass](https://lesspass.com/) to access your password without relying on a third party to store your data.
### Why use a password manager in the first place?
Having a single password for multiple accounts is convenient. What's also convenient, is **using** this password on multiple accounts once you have access to a single one. What might be convenient to you, might also be convenient to others. Many people, [especially celebrities](https://web.archive.org/web/20170225163642/http://uk.businessinsider.com/twitter-says-it-wasnt-hacked-passwords-reused-older-hacks-malware-to-blame-2016-6), fall victim to this trap of comfort.
To counteract this, people are (and should be) using different passwords for different accounts. These passwords differ in a single letter or digit (Twitter: `porridge4president`, GitHub: `poridge5president`, etc.), or they don't match at all (Twitter: `porridge4president`, GitHub: `YouWontGuessThisOne`).
The problem that most likely arises from this technique is called _password chaos_ ([Source](https://encyclopedia2.thefreedictionary.com/password+chaos)):
> _"The confusion that arises when users have many unique passwords."_
The aim of a password manager is [to solve this problem by storing all of your passwords in a single place and securing it with an _ultra secure superpassword!_ (©)](https://www.businessinsider.com/how-to-use-password-manager-store-protect-yourself-hackers-lastpass-1password-dashlane-2017-2?r=DE&IR=T). This way, you can use arbitrary passwords - preferebly gibberish that doesn't make sense to humans (nor machines) - without losing them, as long as you have your _ultra secure superpassword!_ (©) - aka your masterpassword. The benefits are obvious: You get rid of the password chaos problem while staying relatively secure. Eventhough password managers are quite benificial, some people (including myself) see a catch in them.
### Relying on a third party
Relying on third party companies doesn't seem like a big deal. After all, you are probably using some form of cloud service to host your photos. Yet there's a lot of trust involved in letting others handle your private data, especially your passwords. In 2017, [a major password manager got hacked, exposing sensitive data including users and their passwords](https://www.zdnet.com/article/onelogin-hit-by-data-breached-exposing-sensitive-customer-data/). This shows the potential for security breaches in an application that inherently seemed safe. But what if I told you that there is an alternative to this? A password manager that does not store your data at all?
### A Stateless password manager
Recently, I stumbled across [LessPass](https://lesspass.com/#/). LessPass is a password manager that is very different from what I have seen so far. Instead of storing passwords that either you or a random password generator came up with, it computes passwords on the fly, given a website, username, your masterpassword and some options.
![LessPass](../assets/lesspass.gif)
The key here is that LessPass uses a **pure function**, i.e. a function that given the same parameters will always give the same result. Using this technique, there's no need to store your password in a database owned by a large company, nor do you have to sync your passwords between your devices ([but there's an app](https://play.google.com/store/apps/details?id=com.lesspass.android&hl=de)). The computation happens right on your machine, and **only** on your machine. If you want to find out more about how it works under the hood, you can check out [the authors blog post](https://blog.lesspass.com/lesspass-how-it-works-dde742dd18a4#.vbgschksh). He goes into great detail on what alorithm is used to compute your passwords and how to utilize every feature of LessPass.
### Conclusion
Being a little privacy nerd myself, I often think twice about what services I want to use, often even looking into self-hosted alternatives to major products. There are multiple products that offer self hosted solutions to store your passwords, however I also don't even trust _myself_ with such sensitive data either. LessPass eliminates the need to have a third party watch over your data, let alone to store it on their servers.
Loading…
Cancel
Save