From d16530d61a04435fd8cb4d4770c4ac715ac8ef0e Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Sun, 8 Jul 2018 15:46:56 +0200 Subject: Initial commit --- .gitignore | 5 + Gemfile | 10 + Gemfile.lock | 79 ++ _config.yml | 59 ++ _includes/footer.html | 20 + _includes/head.html | 21 + _includes/header.html | 11 + _layouts/default.html | 13 + _layouts/key.html | 15 + _layouts/post.html | 43 ++ _pages/blank.md | 4 + _pages/index.md | 90 +++ _pages/posts.md | 41 ++ _pages/projects.md | 47 ++ _pages/slides.md | 64 ++ _pages/support.md | 44 ++ _plugins/jekyll-less.rb | 9 + _posts/2016-10-01-on-pastebin.md | 80 ++ _posts/2016-10-01-on-systemd.md | 288 ++++++++ _posts/2016-10-01-on-winmail-dat.md | 41 ++ _posts/2016-10-03-install-funtoo.md | 808 +++++++++++++++++++++ _posts/2016-10-25-setup-a-vpn-with-cjdns.md | 212 ++++++ ...2016-10-25-setup-nginx-with-lets-encrypt-ssl.md | 229 ++++++ ...10-31-freebsd-mailserver-part-1-preparations.md | 141 ++++ ...eebsd-mailserver-part-2-mailing-with-postfix.md | 316 ++++++++ ...-freebsd-mailserver-part-3-dovecot-imap-sasl.md | 227 ++++++ ...bsd-mailserver-part-4-message-authentication.md | 159 ++++ ...-31-freebsd-mailserver-part-5-filtering-mail.md | 132 ++++ ...24-freebsd-mailserver-calendars-and-contacts.md | 140 ++++ _posts/2017-09-14-how-to-git.md | 185 +++++ ...-09-28-perl6-creating-a-background-service.adoc | 159 ++++ _posts/2017-11-01-hacktoberfest-2017.adoc | 197 +++++ ...17-11-16-perl6-setting-up-a-raspberry-perl.adoc | 236 ++++++ _posts/2017-12-17-on-cloudflare.adoc | 128 ++++ ...unding-yourself-as-free-software-developer.adoc | 231 ++++++ _posts/2018-02-05-why-perl6.adoc | 280 +++++++ ...l6-introduction-to-application-programming.adoc | 784 ++++++++++++++++++++ _posts/2018-05-07-sparrowdo-getting-started.adoc | 231 ++++++ _projects/bash-scriptkitties-overlay.md | 7 + _projects/lua-subbot.md | 6 + _projects/perl6-app-assixt.md | 6 + _projects/perl6-config.md | 6 + _projects/perl6-dist-helper.md | 6 + _projects/perl6-io-path-dirstack.md | 6 + _projects/perl6-irc-client-plugin-github.md | 6 + _projects/perl6-irc-client-plugin-ignore.md | 6 + _projects/perl6-irc-client-plugin-nickserv.md | 6 + _projects/perl6-irc-client-plugin-urltitle.md | 6 + _projects/perl6-mpd-client.md | 6 + _projects/perl6-musashi.md | 6 + _projects/ruby-tachikoma.md | 7 + ...ing-app-assixt-to-improve-module-development.md | 244 +++++++ css/main.less | 171 +++++ css/pygments.scss | 71 ++ feed.xml | 23 + img/cc-by-sa.png | Bin 0 -> 1621 bytes robots.txt | 3 + 57 files changed, 6371 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 _config.yml create mode 100644 _includes/footer.html create mode 100644 _includes/head.html create mode 100644 _includes/header.html create mode 100644 _layouts/default.html create mode 100644 _layouts/key.html create mode 100644 _layouts/post.html create mode 100644 _pages/blank.md create mode 100644 _pages/index.md create mode 100644 _pages/posts.md create mode 100644 _pages/projects.md create mode 100644 _pages/slides.md create mode 100644 _pages/support.md create mode 100644 _plugins/jekyll-less.rb create mode 100644 _posts/2016-10-01-on-pastebin.md create mode 100644 _posts/2016-10-01-on-systemd.md create mode 100644 _posts/2016-10-01-on-winmail-dat.md create mode 100644 _posts/2016-10-03-install-funtoo.md create mode 100644 _posts/2016-10-25-setup-a-vpn-with-cjdns.md create mode 100644 _posts/2016-10-25-setup-nginx-with-lets-encrypt-ssl.md create mode 100644 _posts/2016-10-31-freebsd-mailserver-part-1-preparations.md create mode 100644 _posts/2016-10-31-freebsd-mailserver-part-2-mailing-with-postfix.md create mode 100644 _posts/2016-10-31-freebsd-mailserver-part-3-dovecot-imap-sasl.md create mode 100644 _posts/2016-10-31-freebsd-mailserver-part-4-message-authentication.md create mode 100644 _posts/2016-10-31-freebsd-mailserver-part-5-filtering-mail.md create mode 100644 _posts/2016-11-24-freebsd-mailserver-calendars-and-contacts.md create mode 100644 _posts/2017-09-14-how-to-git.md create mode 100644 _posts/2017-09-28-perl6-creating-a-background-service.adoc create mode 100644 _posts/2017-11-01-hacktoberfest-2017.adoc create mode 100644 _posts/2017-11-16-perl6-setting-up-a-raspberry-perl.adoc create mode 100644 _posts/2017-12-17-on-cloudflare.adoc create mode 100644 _posts/2017-12-21-funding-yourself-as-free-software-developer.adoc create mode 100644 _posts/2018-02-05-why-perl6.adoc create mode 100644 _posts/2018-03-20-perl6-introduction-to-application-programming.adoc create mode 100644 _posts/2018-05-07-sparrowdo-getting-started.adoc create mode 100644 _projects/bash-scriptkitties-overlay.md create mode 100644 _projects/lua-subbot.md create mode 100644 _projects/perl6-app-assixt.md create mode 100644 _projects/perl6-config.md create mode 100644 _projects/perl6-dist-helper.md create mode 100644 _projects/perl6-io-path-dirstack.md create mode 100644 _projects/perl6-irc-client-plugin-github.md create mode 100644 _projects/perl6-irc-client-plugin-ignore.md create mode 100644 _projects/perl6-irc-client-plugin-nickserv.md create mode 100644 _projects/perl6-irc-client-plugin-urltitle.md create mode 100644 _projects/perl6-mpd-client.md create mode 100644 _projects/perl6-musashi.md create mode 100644 _projects/ruby-tachikoma.md create mode 100644 _slides/perl6-using-app-assixt-to-improve-module-development.md create mode 100644 css/main.less create mode 100644 css/pygments.scss create mode 100644 feed.xml create mode 100644 img/cc-by-sa.png create mode 100644 robots.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c8859f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-metadata +*.bak +css/pygments.base.css diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3973a63 --- /dev/null +++ b/Gemfile @@ -0,0 +1,10 @@ +source "https://rubygems.org" do + gem "bundler" + gem "jekyll" + gem "jekyll-asciidoc" + gem "jekyll-less" + gem "jekyll-sitemap" + gem "pygments.rb" + gem "redcarpet" + gem "therubyracer" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..f2ba2ac --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,79 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + asciidoctor (1.5.6.1) + colorator (1.1.0) + commonjs (0.2.7) + ffi (1.9.18) + forwardable-extended (2.6.0) + jekyll (3.5.2) + addressable (~> 2.4) + colorator (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (~> 1.7) + safe_yaml (~> 1.0) + jekyll-asciidoc (2.1.0) + asciidoctor (>= 1.5.0) + jekyll (>= 2.3.0) + jekyll-less (0.0.4) + jekyll (>= 0.10.0) + less (>= 2.0.5) + jekyll-sass-converter (1.5.0) + sass (~> 3.4) + jekyll-sitemap (1.2.0) + jekyll (~> 3.3) + jekyll-watch (1.5.0) + listen (~> 3.0, < 3.1) + kramdown (1.15.0) + less (2.6.0) + commonjs (~> 0.2.7) + libv8 (3.16.14.19) + liquid (4.0.0) + listen (3.0.8) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + mercenary (0.3.6) + multi_json (1.12.2) + pathutil (0.14.0) + forwardable-extended (~> 2.6) + public_suffix (3.0.0) + pygments.rb (1.2.0) + multi_json (>= 1.0.0) + rb-fsevent (0.10.2) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + redcarpet (3.4.0) + ref (2.0.0) + rouge (1.11.1) + safe_yaml (1.0.4) + sass (3.5.1) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + therubyracer (0.12.3) + libv8 (~> 3.16.14.15) + ref + +PLATFORMS + ruby + +DEPENDENCIES + bundler! + jekyll! + jekyll-asciidoc! + jekyll-less! + jekyll-sitemap! + pygments.rb! + redcarpet! + therubyracer! + +BUNDLED WITH + 1.15.4 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..0d30703 --- /dev/null +++ b/_config.yml @@ -0,0 +1,59 @@ +# Welcome to Jekyll! +# +# This config file is meant for settings that affect your whole blog, values +# which you are expected to set up once and rarely need to edit after that. +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'jekyll serve'. If you change this file, please restart the server process. + +# Site settings +title: Tyil +email: p.spek@tyil.work +description: > # this means to ignore newlines until "baseurl:" + Hi, I'm tyil, and this is my site. I'm a software engineer with a big + interest in Free Software. As such, I spend much time writing and promoting + free software. Occasionally, I'll write an article about something freedom or + software related. +baseurl: "" # the subpath of your site, e.g. /blog +url: "https://www.tyil.nl" # the base hostname & protocol for your site +permalink: pretty +plugins: + - jekyll-asciidoc + - jekyll-sitemap + - pygments.rb + +keep_files: + - img +asciidoctor: + attributes: + icons: font + imagesdir: /img + pygments-style: emacs + pygments-stylesheet: css/pygments.base.css + source-highlighter: pygments +sass: + style: compressed + +# Build settings +markdown: redcarpet + +include: ["_pages"] + +# custom collections +collections: + projects: + output: false + slides: + output: false + +# Give all posts a feed = true attribute for easy feed-generating +defaults: + - scope: + type: articles + values: + categories: article + feed: true + - scope: + type: tutorials + values: + categories: tutorial + feed: true diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000..a050abe --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,20 @@ + diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000..61c8c2d --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,21 @@ + + + + + + + + + {% if page.title %}{{ page.title }} - {% endif %}{{ site.title }} + + {% if page.excerpt.size != 0 and page.excerpt.size > 0 %} + + {% else %} + + {% endif %} + + + + + + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000..2335d7c --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,11 @@ + diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..d923f68 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,13 @@ + + + {% include head.html %} + + {% include header.html %} +
+
+ {{ content }} +
+
+ {% include footer.html %} + + diff --git a/_layouts/key.html b/_layouts/key.html new file mode 100644 index 0000000..62e537e --- /dev/null +++ b/_layouts/key.html @@ -0,0 +1,15 @@ +--- +layout: key +--- + + + + {% include head.html %} + +
+
+{{ content }}
+			
+
+ + diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000..b3d68f4 --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,43 @@ +--- +layout: default +--- + +
+
+

+ {{ page.title }} + {% if page.wip %} + + WIP + + {% endif %} +

+
+
+ {{ content }} +
+ +
diff --git a/_pages/blank.md b/_pages/blank.md new file mode 100644 index 0000000..887598c --- /dev/null +++ b/_pages/blank.md @@ -0,0 +1,4 @@ +--- +permalink: /blank/ +--- + diff --git a/_pages/index.md b/_pages/index.md new file mode 100644 index 0000000..e525dc1 --- /dev/null +++ b/_pages/index.md @@ -0,0 +1,90 @@ +--- +layout: default +permalink: /index.html +title: Personal blog +description: > + Hi, I'm tyil, and this is my site. I'm a software engineer with a big + interest in Free Software. As such, I spend much time writing and promoting + free software. Occasionally, I'll write an article about something freedom or + software related. +--- + +{% for post in site.posts limit:1 %} +{% assign blogpost = post %} +{% endfor %} + +## About me +Freedom-focused hacker. I love everything about free software, and spend much +time contributing to it myself. I occasionally write articles to help other +people getting started with free software, and show the issues with proprietary +software. I'm Active on a number of IRC channels, spread over multiple IRC +networks. Currently I have made over 10 modules for Perl 6, which are all +available on CPAN. I also write a blog post on occasion, with my latest +write-up being "[{{blogpost.title}}]({{blogpost.url}})". + +If you think what I'm doing is awesome, and want to support me, you can do so +through donations. More information about how to donate and what I do with the +donations I receive can be found on the [support][donate] page. + +## Contact +### PGP +My public PGP key is available on on [pgp.mit.edu][pubkey]. The fingerprint +is: + +``` +EB9E A484 1672 2D37 16F5 A799 9ACF E193 FFBC 1F50 +``` + +### OTR +For instant messaging I use OTR where possible. My fingerprints are the following: + +- `973F92EA 4A45DE93 60C2C60E DDC049D5 149B3BE2` XMPP, tyil@national.shitposting.agency +- `B174A02B 1F0A4258 B1527988 770843B4 0582A0D8` IRC, tyil @ DareNET +- `C6025214 E05A4FB6 5E65B900 9CA6A7AF A4A35C48` IRC, tyil @ Freenode +- `80999DD8 22504629 44EC13E3 5C31BF2F FC825703` IRC, tyil @ Rizon + +### Channels +#### Email +Email contact goes via [p.spek@tyil.work][mail]. Be sure to at least sign all +mail you send me. Even better would be encrypted mail using my [PGP +key][pubkey]. + +I do not read my mailboxes very often, so please do not expect a timely +response. If you require a response as soon as possible, please find me on IRC +instead. + +#### IRC +I am mainly active as `tyil` on [Freenode][freenode]. Other networks I frequent +are [DareNET][darenet] and [Rizon][rizon], using the same nick, `tyil`. I +use OTR for private messages on IRC, so be sure you use this if you want to +discuss something in private. + +#### XMPP +I am available via XMPP/Jabber on `tyil@national.shitposting.agency`. Like IRC, +be sure to have OTR enabled if you wish to talk to me. Since my XMPP chats go +via [`BitlBee`][bitlbee], the response time is about the same as via IRC. + +## Other links +- [Mastodon][mastodon] +- [Github][github] +- [DareNET gitlab][c.darenet] +- [Keybase][keybase] +- [LinkedIn][linkedin] + +## RSS +If you'd like to stay up-to-date with my posts, you can subscribe to the [RSS +feed][rss]. + +[bitlbee]: https://www.bitlbee.org/main.php/news.r.html +[c.darenet]: https://c.darenet.org/u/tyil +[darenet]: https://darenet.org +[donate]: /support/ +[freenode]: https://freenode.net +[github]: https://github.com/Tyil +[keybase]: https://keybase.io/tyil +[linkedin]: https://www.linkedin.com/in/patrickspek +[mail]: mailto:p.spek@tyil.work +[mastodon]: https://mastodon.social/web/accounts/34234 +[pubkey]: https://pgp.mit.edu/pks/lookup?op=vindex&search=0x9ACFE193FFBC1F50 +[rizon]: https://rizon.net +[rss]: https://www.tyil.nl/feed.xml diff --git a/_pages/posts.md b/_pages/posts.md new file mode 100644 index 0000000..b99dec8 --- /dev/null +++ b/_pages/posts.md @@ -0,0 +1,41 @@ +--- +layout: default +permalink: /posts/ +title: Blog posts +description: > + I occasionally write blogposts about things I find interesting. These are + usually programming, security or privacy related. +--- + +## Blog posts +I sometimes write articles to refer to. It saves a lot of time compared to +explaining the same thing over and over again. As such, most articles will +probably be little rants. All of the articles I wrote have been made public on +my site, and can be found below, in alphabetical order. + +If you wish to respond to any article, whether it be criticism, reporting +mistakes or simply because you want to discuss the points, feel free to send me +an email. My email address is listed [on the homepage][home]. If you do, +consider adding a PGP signature or sending it encrypted with [my pgp key][pgp]. +All feedback is greatly appreciated, so do not hesitate to contact me to give +me yours. + +These articles are available under the [Creative Commons (CC BY-SA +3.0)][cc-by-sa] license, which means you are free to use it for any purpose so +long as you keep attribution to me (and preferably also just link to the +original article) and do not relicense the article. + +I'd also like to note that these articles reflect my opinion, and only mine. +Please refrain from accusing other people of holding my opinion for simply +being referenced in my articles. + +{% for post in site.posts %} +{% if post.wip %} + {% continue %} +{% endif %} +* [{{ post.title }}]({{ post.url }}) {{ post.date | date: "%Y-%m-%d" }} +{% endfor %} + +[cc-by-sa]: https://creativecommons.org/licenses/by-sa/3.0/ +[home]: / +[pgp]: http://pgp.mit.edu/pks/lookup?op=vindex&search=0x9ACFE193FFBC1F50 diff --git a/_pages/projects.md b/_pages/projects.md new file mode 100644 index 0000000..faa0aa5 --- /dev/null +++ b/_pages/projects.md @@ -0,0 +1,47 @@ +--- +layout: default +permalink: /projects/ +title: Software projects +description: > + Here is a list of all projects I worked on that I deem good or important + enough to publish here. This list won't always be complete, but it's good + enough for a quick overview. +--- + +# Projects +Here is a list of all projects I worked on that I deem good or important enough +to publish here. This list won't always be complete, but you can check [my +Github profile][github] if you're interested to see more. + +All of the projects listed below are [Free software][free-software], and are +made in my free time. Contributions in any form are welcome. This includes, but +is not limited to, pull/merge requests, bug reports are [financial +support][support]. You can also come discuss the projects and possible issues +you have found with them on IRC or contact me through email. Details for both +can be found [on the homepage][home]. + + + + + + + + + + + + {% for project in site.projects %} + + + + + + + {% endfor %} + +
ProjectLanguage(s)LicenseRepository
{{ project.title }}{{ project.langs }}{{ project.license }}{{ project.repo }}
+ +[free-software]: https://en.wikipedia.org/wiki/Free_software +[github]: https://github.com/tyil +[home]: / +[support]: /support/ diff --git a/_pages/slides.md b/_pages/slides.md new file mode 100644 index 0000000..d03fd41 --- /dev/null +++ b/_pages/slides.md @@ -0,0 +1,64 @@ +--- +layout: default +permalink: /slides/ +title: Presentations and Slides +description: > + Here is a list of the slides I've used for presentations. The slides are in + Markdown format, and can be compiled into a working slideshow using + reveal-md. The slides here are the original sources, and include speaker + notes. +--- + +# Presentations and Slides +Here is the list of presentations I've given and the slideshows I've used for +them. If there are video sources available, they will be linked to as well. + +The slides are written in Markdown, and can be compiled to a usable slideshow +using [`reveal-md`][reveal-md]. The slide sources are complete, including the +speaker notes. + +I've only given a single presentation right now, but I plan to do more of them +at various events, such as [FOSDEM][fosdem]. I want to give more presentations +to get better at presenting people and getting them interested in programming +languages and aspects that I am also interested in. It's also a great way to +promote my favourite programming language, [Perl 6][perl6]. + + + + + + + + + + + {% for slides in site.slides %} + + + + + + {% endfor %} + +
EventDateMaterials
{{ slides.event }} + {% assign day = slides.date | date: "%-d" %} + {% case day %} + {% when '1' or '21' or '31' %}{{ day }}st + {% when '2' or '22' %}{{ day }}nd + {% when '3' or '23' %}{{ day }}rd + {% else %} + {{ day }}th + {% endcase %} + {{ slides.date | date: "of %B, %Y" }} + + + Slides + + {% if slides.video %} + , Video + {% endif %} +
+ +[reveal-md]: https://github.com/webpro/reveal-md +[fosdem]: https://fosdem.org/ +[perl6]: https://perl6.org/ diff --git a/_pages/support.md b/_pages/support.md new file mode 100644 index 0000000..d65e0c3 --- /dev/null +++ b/_pages/support.md @@ -0,0 +1,44 @@ +--- +layout: default +permalink: /support/ +title: Funding me +description: > + Thanks for considering to support my work. It's much appreciated, and it + helps me to spend more time writing articles, tutorials, free software and + promote more free software. +--- + +# Supporting me +Thanks for considering to support my work. It's much appreciated, and it helps me +to spend more time writing articles, tutorials, free software and promote more +free software. + +I think free software is very important to have around, and all software made +should be released as free software. As such, I will continue to keep working +on free software and it's promotion regardless of how much I receive in +(financial) funding. However, more funding allows me to spend more time on +this. + +## Funding platforms +I've set up a number of accounts on donation platforms. This way, you can +decide which platform you trust the most. The platforms I'm available on are: + +- [Liberapay](https://liberapay.com/tyil/donate) +- [MakerSupport](https://www.makersupport.com/tyilanmenyn/pledge) +- [Patreon](https://www.patreon.com/tyil) + +If there are other platforms which you consider to be better, do let me know. I +am always open to suggestions, and I will try to make time to review other +platforms if possible. Such suggestions will also be incorporated in [my +article on Free software funding][article-funding]. + +## What's it used for? +Your donations will go towards paying the server I use to work and test things +on, `hyve2.tyil.net`. + +If funding allows, I can look into possibilities to take time off of my day +time job in order to spend more time on free software work. It would also allow +me take more time off in order to attend conferences or give presentations on +my free software projects. + +[article-funding]: /articles/funding-yourself-as-free-software-developer/ diff --git a/_plugins/jekyll-less.rb b/_plugins/jekyll-less.rb new file mode 100644 index 0000000..4950c11 --- /dev/null +++ b/_plugins/jekyll-less.rb @@ -0,0 +1,9 @@ +## +# +# `jekyll-less` is loaded like this to fix a certain bug +# (https://github.com/zroger/jekyll-less/issues/15). +# +## +require "jekyll-less" + +@@mtimes = {} diff --git a/_posts/2016-10-01-on-pastebin.md b/_posts/2016-10-01-on-pastebin.md new file mode 100644 index 0000000..775cbe4 --- /dev/null +++ b/_posts/2016-10-01-on-pastebin.md @@ -0,0 +1,80 @@ +--- +layout: post +title: On Pastebin +date: 2016-10-01 10:20:27 +0200 +tags: Article Harmful Pastebin +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# Pastebin +Pastebin offers itself as a gratis paste service. Although it is probably the +most well known option out there, it is certainly not the best. + +## The security issue +Pastebin has a couple of issues that harm the visitor's security. This on +itself should be considered such a bad practice that no-one should consider +their service at all. + +### Cloudflare +Cloudflare is a [MITM][mitm]. It completely breaks the secure chain of TLS on +the web, and should not be used. Any service still using Cloudflare should be +shunned. There is [another article][cloudflare] on this site which has more +information on this specific issue. In addition, Cloudflare can be considered a +privacy issue for the same reasons, as is detailed below. + +### Advertisements +Another issue with regards to security on pastebin are the advertisements. +While it can be argued that "they need to make money somehow", using ads always +seems like the worst possible solution. Especially given the way they're +serving it. The past couple years have shown that advertisements on the web are +easily abused to serve malware to good netizens who decided to not block all +ads. + +A rant on the state of ads might be appropriate, but this article is +specifically about Pastebin, so I will just keep it at "third party +advertisements are a security risk, avoid sites who use them" + +## The privacy issue +Apart from their security issues, Pastebin also offers some privacy issues. As +stated above, they make use of Cloudflare. This means that whenever you visit +them, Cloudflare takes note of this. They may even decide that you need to +perform some additional tasks in order to be allowed to the resource. This +doesn't happen to most users, but if you're using any anonymization practices, +this will happen almost every time you visit a site behind Cloudflare. + +In addition to telling Cloudflare, you will also tell another third party, +Google, in case this "additional step" is required. This is done via the new +reCaptcha system which will inform Google of almost every detail of your +browser and the behaviour used to solve the puzzle. Incredibly useful for +fingerprinting you accross multiple locations. + +### Then there is Tor +But, if you're using an anonymization proxy such as Tor, even if you do not +care about the Cloudflare issue, and you solve the "security check" presented +to you, Pastebin still refuses to offer you their service. If they are going to +refuse you service, they should tell you up front, not after you have already +informed two other harmful parties of your attempt of accessing the resource. + +Actually, they should not. They should simply not require you to give up your +privacy and serve you the content you were looking for. Blocking resources to a +certain group of users is simply censorship, and should not be the status quo +on the free internet. + +## Alternatives +Luckily, there are plenty of alternatives that do not treat their users with +such disrespect. I ask anyone who is still using Pastebin to stop doing this, +and use any of the alternatives. + +* [0bin.net](https://0bin.net/) +* [cry.nu][crynu] (works like termbin: `nc cry.nu 9999 < file`) +* [ix.io][ix] +- [p.tyil.nl][tyilnl] (worsk like termbin: `nc p.tyil.nl 9999 < file`) + +[cloudflare]: /articles/on-cloudflare/ +[crynu]: https://cry.nu +[hastebin]: http://hastebin.com +[ix]: http://ix.io/ +[mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack +[termbin]: http://termbin.com +[tyilnl]: / diff --git a/_posts/2016-10-01-on-systemd.md b/_posts/2016-10-01-on-systemd.md new file mode 100644 index 0000000..b85c82f --- /dev/null +++ b/_posts/2016-10-01-on-systemd.md @@ -0,0 +1,288 @@ +--- +layout: post +title: On Systemd +date: 2016-10-01 10:20:27 +0200 +tags: Article Harmful Systemd +authors: + - ["Patrick Spek", "http://tyil.work"] + - ["Samantha McVey", "https://cry.nu"] +--- + +# Systemd +Systemd once presented itself as being the next generation init system for +GNU+Linux. When the project started it seemed to be headed in a good direction. +Unfortunately, it quickly became clear that systemd's goal was not only to +bring you a quick, new init system. It planned to do so much more. This was +part of the plan, since init systems were generally considered to be in a bad +state overall it was quickly accepted by most mainstream GNU+Linux +distributions. What was at first only an init system became so much more: +systemd-logind was made to manage tty's, systemd-resolvd was added to act as a +caching DNS server. Even networking was added with systemd-networkd to manage +network interfaces. + +**DISCLAIMER**: Systemd is a fast moving project, this may result in +information here to becoming outdated. If you find any information that is no +longer correct, please contact me. You can find my contact details [on my +homepage][tyil]. + +## Technical issues +### Security +From experience, we have seen that systemd's creator, Lennart Poettering, will +try to assimilate any functionality he can find and add it into systemd. This +causes systemd to have a large surface area of attack, adding to and magnifying +security attack vectors. An init system should be exactly the opposite. To +compound this issue, we have bugs like [the user-level DoS][systemd-dos], +which seem to indicate that the software is hardly tested or written by +programmers who don't use best practices. + +### POSIX +POSIX compliance. Systemd developers seem to detest it. Their common argument +against retaining POSIX compliance is that "systemd must break POSIX compliance +in order to further the development of GNU+Linux userland utilities". While +this may be true in some sense, it is a very bad idea to ignore POSIX +altogether. + +POSIX is one of the reasons that most applications running on GNU+Linux and +other Unix like systems are very portable. It's a standard that most OS's and +distro's try to meet, making it easy to port software. + +[natermeer on Reddit][reddit-natermeer] said +> POSIX has almost no relevance anymore. +> +> [...] +> +> If you care about portability you care about it running on OS X and Windows +> as well as your favorite \*nix system. POSIX gains you nothing here. A lot +> of the APIs from many of these systems will resemble POSIX closely, but if +> you don't take system-specific differences into account you are not going +> to accomplish much. + +> I really doubt that any Init system from any Unix system uses only POSIX +> interfaces, except maybe NetBSD. All of them are going to use scripts and +> services that are going to be running commands that use kernel-specific +> features at some point. Maybe a init will compile and can be executed on +> pure POSIX api, but that is a FAR FAR cry from actually having a booted and +> running system. + +Which was replied to by [aidanjt][reddit-aidanjt] +> Wrong, both OS X and Windows have POSIX support, although Window's is emulated, +> OS X certainly is not, it's fully POSIX compliant. and b) POSIX doesn't have to +> work identically everywhere, it only has to be more or less the same in most +> places and downstream can easily patch around OS-specific quirks. Even +> GNU/Linux and a bunch of the BSDs are merely regarded as 'mostly' POSIX +> compliant, after all. But if you ignore POSIX entirely, there's ZERO hope of +> portability. +> +> Actually sysvinit is very portable, init.c only has 1 single Linux header which +> has been #ifdef'ed, to handle the three-finger-salute. You see, init really +> isn't that complicated a programme, you tell the kernel to load it after it's +> done it's thing, init starts, and loads distro scripts which starts userspace +> programmes to carry on booting. No special voodoo magic is really required. +> POSIX is to thank for that. POSIX doesn't need to be the only library eva, it +> only needs to handle most of the things you can't do without, without having to +> directly poke at kernel-specific interfaces. +> +> This is why with POSIX, we can take a piece of software written for a PPC AIX +> mainframe, and make it work on x86 Linux without a complete rewrite, usually +> with only trivial changes. + +### Dependencies and unportability +Another common issue with systemd is that applications have started to +needlessly depend on it, forcing systemd onto users that do not wish to use +systemd for obvious reasons outlined here, reasons outside of this article, or +simply being unable to use it. Because systemd complies to no cross-platform +standard and uses many features only available in recent Linux version, it's +either very hard or impossible to implement systemd in some circumstances. + +The list of features it requires is no small one either, as you can see in the +list [posted by ohset][reddit-ohet]: + +- `/dev/char` +- `/dev/disk/by-label` +- `/dev/disk/by-uuid` +- `/dev/random` +- `/dev/rtc` +- `/dev/tty0` +- `/proc/$PID/cgroup` +- `/proc/${PID}/cmdline` +- `/proc/${PID}/comm` +- `/proc/${PID}/fd` +- `/proc/${PID}/root` +- `/proc/${PID}/stat` +- `/proc/cmdline` +- `/sys/class/dmi/id` +- `/sys/class/tty/console/active` +- `BTRFS_IOC_DEFRAG` +- `CLONE_xxx` +- `F_SETPIPE_SZ` +- `IP_TRANSPORT` +- `KDSKBMODE` +- `O_CLOEXEC` +- `PR_CAPBSET_DROP` +- `PR_GET_SECUREBITS` +- `PR_SET_NAME` +- `PR_SET_PDEATHSIG` +- `RLIMIT_RTPRIO` +- `RLIMIT_RTTIME` +- `SCHED_RESET_ON_FORK` +- `SOCK_CLOEXEC` +- `TIOCLINUX` +- `TIOCNXCL` +- `TIOCVHANGUP` +- `VT_ACTIVATE` +- `\033[3J` +- `audit` +- `autofs4` +- `capabilities` +- `cgroups` +- `fanotify` +- `inotify` +- `ionice` +- `namespaces` +- `oom score adjust` +- `openat()` and friends +- `selinux` +- `settimeofday()` and its semantics +- `udev` +- `waitid()` +- numerous GNU APIs like `asprintf` + +This made [Gnome][gnome] unavailable for a long time to BSD users and GNU+Linux +users who wanted to remain with a sane and proven system. Utilities like +[Gummiboot][gummiboot] are now being absorbed by systemd too. It is only a +matter of time before you can no longer use this utility without a systemd init +behind it. There are too many examples of software to list, which are being +assimilated or made unavailable by lazy or bad developers who choose to depend +on systemd for whatever reason. + +### Speed +The main selling point many systemd users hail all the time, is speed. They +place an unusual high amount of value on being a couple seconds faster on boot. +Systemd gains this speed gain by using parallelization, and many think this is +unique to systemd. Luckily for those who want to stick to a more sane system, +this is false. Other init systems, such as [OpenRC][openrc], used by +[Funtoo][funtoo], and [runit][runit], used by [Voidlinux][voidlinux] both +support parallel startup of services. Both these systems use small and +effective shell scripts for this, and support startup dependencies and the +like. Systemd brings nothing new to the init world, it just advertises these +features more agressively. + +### Modularity +The UNIX principle, *make an application perform one task very well*, seems to +be very unpopular among systemd developers. This principle is one of the +reasons why UNIX based systems have gotten so popular. Yet, the systemd +developers seem to despise this principle, and even try to argue that systemd +actually is modular because **it compiles down to multiple binaries**. This +shows a lack of understanding, which would make most users uneasy when they +consider that these people are working on one of the most critical pieces of +their OS. + +The technical problem this brings is that it is very hard to use systemd with +existing tools. `journald` for instance doesn't just output plain text you can +easily filter through, save or apply to a pager. I decides for you how to +represent this information, even if this might be an ineffective way to go +about it. + +### Binary logs +Hailed by systemd users and developers as a more efficient, fast and secure way +to store your logs, it is yet another middle finger to the UNIX principles, +which state that documents intended for the user should be human readable. +Binary logs are exactly not that. This forces you to use the tools bundled with +systemd, instead of your preferred solution. This means you need a system with +systemd in order to read your logs, which you generally need the most when the +system that generated it crashed. Thanks to systemd, these logs are now useless +unless you have another systemd available for it. + +These logs are also very fragile. It is a common "issue" to have corrupted logs +when using systemd. Corrupted is here within quotes because the systemd +developers do not recognize this as a bug. Instead, you should just rotate your +logs and hope it does not happen again. + +The usual counter to this issue is that you *can* tell systemd to use another +logger. However, this does not stop `journald` from processing them first or +just not having `journald` at all. As systemd is not modular, you will always +have all the pieces installed. It should also be noted that this is a +*workaround*, not a fix to the underlying problem. + +## Political issues +### Aggressively forced upon users +A point that has made many systemd opponents very wary of this huge piece of +software is the way it was introduced. Unlike most free software packages, +systemd was forced into the lives of many users by getting hard dependencies on +them, or simply absorbing a critical piece of software by the use of political +power. The two most prominent pieces of software where this has happened are +[Gnome][gnome] and [`udev`][udev]. + +The Gnome developers made a hard dependency on systemd. This in effect made +every gnome user suddenly require systemd. As a result, FreeBSD had to actually +drop Gnome for a while, as systemd does not run outside of GNU+Linux. + +The other, `udev`, was a critical piece of software to manage devices in +GNU+Linux. Sadly, some political power was shown by Red Hat and `udev` got +absorbed into systemd. Luckily, the Gentoo guys saw this issue and tried to +resolve it. As the systemd developers dislike anything that's not systemd +itself, they stubbornly refused the patches from the Gentoo folks which would +keep `udev` a single component (and thus usable without systemd). In the end, +the Gentoo developers forked `udev` into [`eudev`][eudev]. + +### Unwillingness to cooperate +Whenever someone from outside the systemd fangroups steps up to actually +improve systemd in whatever way, the systemd devs seem to be rather +uncooperative. It is not uncommon for developers from other projects to make a +change in order for their projects (and usually others) to improve. This +removes a lot of the cost for the systemd maintainers to deal with all the +issues created they are creating. + +There are some references to the systemd developers being against changes that +might make systemd less of a problem, but these changes are usually denied with +petty excuses. + +- https://lists.freedesktop.org/archives/systemd-devel/2012-June/005466.html +- https://lists.freedesktop.org/archives/systemd-devel/2012-June/005507.html + +## How to avoid it +### Choosing a better OS or distribution +Nowadays, the only way to avoid it without too much trouble, is by simply +choosing a better OS or distro that does not depend on systemd at all. There +are a few choices for this: + +- \*BSD ([FreeBSD][freebsd], [OpenBSD][openbsd], and others) +- [Devuan][devuan] +- [Funtoo][funtoo] +- [Voidlinux][voidlinux] + +It is a shame that it renders a very large chunk of the GNU+Linux world +unavailable when choosing a distro, but they have chosen laziness over a +working system. The only way to tell them at this point that they have made a +wrong decision, is to simply stop using these distros. + +### More links + +- [Broken by design: systemd][broken-systemd] +- [Without systemd][without-systemd] +- [systemd is the best example of Suck][suckless-systemd] +- [Thoughts on the systemd root exploit][agwa-systemd-root-exploit] (In response to [CVE-2016-10156][cve-2016-10156]) +- ["systemd: Please, No, Not Like This"](https://fromthecodefront.blogspot.nl/2017/10/systemd-no.html) + +[agwa-systemd-root-exploit]: https://www.agwa.name/blog/post/thoughts_on_the_systemd_root_exploit +[broken-systemd]: http://ewontfix.com/14/ +[cve-2016-10156]: http://www.openwall.com/lists/oss-security/2017/01/24/4 +[devuan]: https://devuan.org/ +[eudev]: https://wiki.gentoo.org/wiki/Eudev +[freebsd]: https://www.freebsd.org/ +[funtoo]: http://www.funtoo.org/Welcome +[gentoo]: https://gentoo.org +[gnome]: http://www.gnome.org/ +[gummiboot]: https://en.wikipedia.org/wiki/Gummiboot_(software) +[openbsd]: https://www.openbsd.org/ +[openrc]: https://en.wikipedia.org/wiki/OpenRC +[reddit-aidanjt]: https://www.reddit.com/r/linux/comments/132gle/eli5_the_systemd_vs_initupstart_controversy/c72saay +[reddit-natermeer]: https://www.reddit.com/r/linux/comments/132gle/eli5_the_systemd_vs_initupstart_controversy/c70hrsq +[reddit-ohet]: https://www.reddit.com/r/linux/comments/132gle/eli5_the_systemd_vs_initupstart_controversy/c70cao2 +[runit]: http://smarden.org/runit/ +[suckless-systemd]: http://suckless.org/sucks/systemd +[systemd-dos]: https://github.com/systemd/systemd/blob/b8fafaf4a1cffd02389d61ed92ca7acb1b8c739c/src/core/manager.c#L1666 +[tyil]: http://tyil.work +[udev]: https://wiki.gentoo.org/wiki/Eudev +[voidlinux]: http://www.voidlinux.eu/ +[without-systemd]: http://without-systemd.org/wiki/index.php/Main_Page diff --git a/_posts/2016-10-01-on-winmail-dat.md b/_posts/2016-10-01-on-winmail-dat.md new file mode 100644 index 0000000..2522614 --- /dev/null +++ b/_posts/2016-10-01-on-winmail-dat.md @@ -0,0 +1,41 @@ +--- +layout: post +title: On winmail.dat +date: 2016-10-01 10:20:27 +0200 +wip: true +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# winmail.dat +This article is intended for sysadmins who run email systems and those who +maintain the Outlook instances for their workforce. If you do not belong into +either of these categories, the following article is probably not too useful. + +If you are one of the many people that suffers from a sysadmin who has yet to +fix the `winmail.dat` issues on his network, you can kindly redirect them here +and hope that they are kind enough to improve their services. If they do not, +you may want to look for a better sysadmin. + +## What is this `winmail.dat`? +A `winmail.dat` is a file that Outlook will attach if an Outlook user sends an +email containing actual attachments or any kind of markup unless Outlook has +been configured not to do so. It is a binary format that holds all the +information to the markup used in the email and the actual attachment that the +user was trying to send. As is typical with Microsoft, this is incompatible +with other Microsoft products. It will only "fix" itself if the receiver is +also using Outlook. + +## Why should I care? +This means that recipients of any mail sent using such a badly configured +Outlook instance cannot see any markup used by the sender, nor can the +recipient see any attachment. Most people can live without the markup, but not +being able to see the actual attachments is generally a pretty big issue. + +Now, there are shady tools available to try and decode these `winmail.dat` +files, but these will not work correctly in all circumstances. Furthermore, an +end-user should not be required to depend on a shady tool to fix the symptom of +a misconfigured email client from another party. + +## How can I fix this? + diff --git a/_posts/2016-10-03-install-funtoo.md b/_posts/2016-10-03-install-funtoo.md new file mode 100644 index 0000000..6526093 --- /dev/null +++ b/_posts/2016-10-03-install-funtoo.md @@ -0,0 +1,808 @@ +--- +title: Install Funtoo +wip: true +date: 2016-10-03 18:05:59 +tags: Tutorial Installation Funtoo +layout: post +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# Install Funtoo +It has come to my attention that many people consider installing Gentoo, and in +effect, Funtoo, a hard task to complete. Some people have also shown interest in +my particular setup. In addition, my favourite English teacher, Anne the Lion, +has tasked us students to write a tutorial to assess our English skills. + +As such, I have written this tutorial to show people my installation steps, and +mentally please my teacher. If you have any suggestions or criticism, please +find me on IRC. The networks I frequent and the nickname I use can be found on +[my homepage][tyil]. + +## Assumptions +This tutorial assumes a few things from you. If you do not meet most of these +assumptions, this guide is probably not for you. You can of course still read +it, however, there might be a lot of jargon you do not understand, making the +tutorial more complex to understand. + +- You have experience with GNU+Linux +- You know your way in the terminal +- You are not afraid of using text-based applications +- You have experience reading through manuals and documentation +- You are not afraid to spend some hours on IRC to help you troubleshoot issues + +## Installing Funtoo +This tutorial will guide you through a not-so-basic installation of the Funtoo +GNU+Linux distribution. It is based on one of my own installations, but +slightly simplified. + +### The live environment +Before you can get started with setting up the system, you will need something to +set it up with. We will be using a live environment for this purpose. My +personal choice for this task is [the Gentoo-based SystemRescueCD][sysrescuecd]. + +You can use any other live environment your prefer, however, this tutorial will +only guide you into preparing the System Rescue CD. + +#### Getting the live USB image +You can download the System Rescue CD at one of the following locations: + +- [Funtoo][Funtoo] +- [Osuosl][osuosl] + +#### Setting up the live USB +After downloading the image, mount it somewhere: + +{% highlight sh %} +mount path/to/sysrescuecd.iso /mnt/cdrom +{% endhighlight %} + +Once it is mounted, you can run the installer bundled with the image by running + +{% highlight sh %} +/mnt/cdrom/usb_inst.sh +{% endhighlight %} + +Select the right device and wait for the installer to finish up. + +#### Booting the USB +To begin using the live environment so you can install something with it, boot +it up. Make sure the USB is in the machine, and reboot it. Enter the BIOS/UEFI +settings and make sure to either make the USB device a higher boot priority, or +select it to be the boot device for one boot. The availability and location of +these options differs per machine, so be sure to check the manual or look around +online for instructions if it is not clear to you. + +### Hardware preparation +The hardware you are installing on needs to be prepared. This could mean +manually configuring your hardware RAID if you use this and configuring other +exotic setups. This tutorial will not go into details for such setups, as there +is a near infinite amount of possible options. Instead, you should stick to +simply configuring your storage device. + +The size of your storage device should be at least 35GB to be safe and have +some space for personal data. The partitioning layout this guide is aiming for +is the following: + +{% highlight plain %} +DEVICE FILESYSTEM SIZE MOUNTPOINT +sda + sda1 fat32 2GB /boot + sda2 lvm + funtoo0-root xfs 8GB / + funtoo0-home zfs /home + funtoo0-sources ext4 3GB /usr/src + funtoo0-portage reiserfs 2GB /usr/portage + funtoo0-swap swap + funtoo0-packages xfs 10GB /var/packages + funtoo0-distfiles xfs 10GB /var/distfiles +{% endhighlight %} + +If you already an advanced user, you are of course free to diverge from the +guide here. + +#### Partition the drive +The first part is to setup partitions. This can be done by calling `gdisk +/dev/sda`. + +Let us wipe the entire disk and start with a clean slate. You can do this by +typing `o` and pressing enter. When asked wether you are sure, type `y` and +enter again. + +Now you are going to create two partitions, one for `/boot` and one for +[`lvm`][wikipedia-lvm]. Following is a list of what to enter. `` denotes +pressing the enter key. + +- `n` `` +- `` +- `` +- `+500M` `` +- `EF00` `` + +- `n` `` +- `` +- `` +- `` +- `` + +#### Setting up encryption +Any system should be safe. Encryption is just a small part, but in my opinion +very important. We are going to encrypt the entire `lvm` partition using +[`luks`][wikipedia-luks]. The frontend tool to be used for this is +[`cryptsetup`][wikipedia-cryptsetup]: + +{% highlight sh %} +cryptsetup --cipher aes-xts-plain64 --hash sha512 --key-size 256 luksFormat /dev/sda2 +{% endhighlight %} + +`cryptsetup` will ask you for a passphrase. Make sure to use a good one, +preferably at least 20 characters in length. + +Once the partition has been encrypted, open the device so it can be used by +invoking `cryptsetup luksOpen /dev/sda2 dmcrypt_lvm`. + +#### Set up LVM +Once the encrypted partition has been unlocked, you can setup `lvm` on it. To +initialize an lvm volume on this partition, run the following: + +{% highlight sh %} +pvcreate /dev/mapper/dmcrypt_lvm +vgcreate funtoo0 /dev/mapper/dmcrypt_lvm +{% endhighlight %} + +The lvm volume has now been prepared, and you can start adding volumes to it to +be used as partitions. It is recommended to have a swap partition as well. The +size of this partition depends on the amount of RAM you have available. Due to +my availability to big disks, I generally opt for a swap partition the same size +as my total RAM in the machine. To make the tutorial work for this as well, a +subshell is called to figure out the size of the swap partition. + +{% highlight sh %} +lvcreate -L8G -n root funtoo0 +lvcreate -L3G -n sources funtoo0 +lvcreate -L2G -n portage funtoo0 +lvcreate -L10G -n packages funtoo0 +lvcreate -L10G -n distfiles funtoo0 +lvcreate -L$(free -h | grep -i mem: | awk '{print $2}') -n swap funtoo0 +lvcreate -l 100%FREE -n home funtoo0 +{% endhighlight %} + +#### Create filesystems +Now you are ready to create usable filesystems on the partitions: + +{% highlight sh %} +mkfs.vfat -F32 /dev/sda1 +mkfs.xfs /dev/mapper/funtoo0-root +mkfs.xfs /dev/mapper/funtoo0-packages +mkfs.xfs /dev/mapper/funtoo0-distfiles +mkfs.reiserfs /dev/mapper/funtoo0-portage +mkfs.ext4 /dev/mapper/funtoo0-sources +mkswap /dev/mapper/funtoo0-swap +{% endhighlight %} + +If you're thinking at this point "where's my home partition?", it's not +initialized here. [ZFS][wikipedia-zfs] requires custom kernel modules which will +be built later, after the initial kernel has been compiled. + +#### Mount the filesystems +Next up is mounting all filesystems so you can install files to them. First, you +mount the root filesystem: + +{% highlight sh %} +mount /dev/mapper/funtoo0-root /mnt/gentoo +{% endhighlight %} + +Now you can add some directories for the other mountpoints. This can be done in +one well-made `mkdir` invocation: + +{% highlight sh %} +mkdir -p /mnt/gentoo/{boot,home,usr/{portage,src},var/{tmp,distfiles,packages},tmp} +{% endhighlight %} + +Next you can mount all other mountpoints on the new directories: + +{% highlight sh %} +mount /dev/sda1 /mnt/gentoo/boot +mount /dev/mapper/funtoo0-portage /mnt/gentoo/usr/portage +mount /dev/mapper/funtoo0-sources /mnt/gentoo/usr/src +mount /dev/mapper/funtoo0-distfiles /mnt/gentoo/var/distfiles +mount /dev/mapper/funtoo0-packages /mnt/gentoo/var/packages +{% endhighlight %} + +Let's also enable swap and ramdisks for the temporary storage directories: + +{% highlight sh %} +swapon /dev/mapper/funtoo0-swap +mount -t tmpfs none /mnt/gentoo/tmp +mount --rbind /mnt/gentoo/tmp /mnt/gentoo/var/tmp +{% endhighlight %} + +### Initial setup +Now that all mountpoints have been set up, installation of the actual OS can +begin. This is done by downloading a "stage 3" tarball containing a bare minimal +Funtoo installation and extracting it with the right options. + +The stage 3 tarball can be downloaded from [build.funtoo.org][funtoo-build]. It +is easiest to download and extract the tarball in the root filesystem, so let's +do that: + +{% highlight sh %} +cd /mnt/gentoo +wget http://build.funtoo.org/funtoo-current/x86-64bit/generic_64/stage3-latest.tar.xz +tar xpf stage3-latest.tar.xz +{% endhighlight %} + +Once extraction is complete, you can opt to delete the tarball as it is no +longer needed at this point. You can delete it by invoking `rm stage3-latest.tar.gz`. + +### System configuration +You now have a bare Funtoo installation ready on your machine. But before you +can actually use it, you should do some configuration. + +#### Chrooting +Before you get to the configuration part, you should [`chroot`][wikipedia-chroot] +into the system. This allows you to enter your new Funtoo installation before it +can properly boot. If your system ever breaks and you are unable to boot into it +anymore, you can redo the mounting section of this guide and this chrooting +section to get into it and resolve your issues. + +The chrooting requires a couple extra mounts, so the chroot can interface with +the hardware provided by the system above it: + +{% highlight sh %} +mount -t proc none proc +mount --rbind /dev dev +mount --rbind /sys sys +{% endhighlight %} + +Once these mountpoints are set, you will need to copy over `resolv.conf` so the +chroot can resolve DNS names: + +{% highlight sh %} +cp /etc/resolv.conf etc +{% endhighlight %} + +Now that everything is prepared in the chroot, you can enter your Funtoo +installation using the following: + +{% highlight sh %} +chroot . bash -l +{% endhighlight %} + +#### Set up the portage tree +The portage tree is a collection of files which are used by the package manager +to find out which software it can install, and more importantly, how to install +it. + +The default location in Funtoo for your portage tree is in `/usr/portage`. +However, as I use multiple sources for my portage tree, I prefer to set it up +under `/usr/portage/funtoo`. This is not a required step, but advised nonetheless. + +In order to change this, open up `/etc/portage/repos.conf/gentoo` in your +favourite editor. Funtoo comes with [`vi`][wikipedia-vi], +[`nano`][wikipedia-nano] and [`ed`][wikipedia-ed] by default. `ed` is +recommended as the standard editor. After opening the file, change the +`location` key to point to `/usr/portage/funtoo`. + +When you have modified `/etc/portage/repos.conf/gentoo` (or not, if you do not +want to change this default), continue to download your first version of the +portage tree: + +{% highlight sh %} +emerge --sync +{% endhighlight %} + +Everytime you want to update your system, you will have to do an `emerge --sync` +to update the portage tree first. It is managed by [`git`][wikipedia-git], which +can bring some side effects. The most notable one is that the tree will grow +over time with old commit data. If you wish to clean this up, simply +`rm -rf /usr/portage/* && emerge --sync` to regenerate it from scratch + +#### Setting up your system settings +In order to make the system work properly, some setup has to be performed. This +will involve editing some text files, for which you can use your favourite +editor again. + +##### /etc/fstab +We will begin with the most important one, `/etc/fstab`. This file holds +information on your mountpoints. Some of the mountpoints are best configured +with UUIDs, because the device enumeration can sometimes differ. If you have +multiple storage devices in your system, this could as well be a hard +requirement. UUIDs are unique to each storage device, so you will have to figure +out your UUIDs yourself. You can do this by running `lsblk -o +UUID`. Take note +of the UUID of your boot device. + +Once you know the UUID, open up `/etc/fstab` with whatever editor you feel +comfortable with and make it look like the following block of text. Do not +forget to update the UUIDs! + +{% highlight plain %} +# boot device +/dev/sda1 /boot vfat noauto,noatime 1 2 + +# lvm volumes +/dev/mapper/funtoo0-root / xfs rw,relatime,data=ordered 0 1 +/dev/mapper/funtoo0-portage /usr/portage reiserfs defaults 0 0 +/dev/mapper/funtoo0-sources /usr/src ext4 noatime 0 1 +/dev/mapper/funtoo0-packages /var/packages xfs defaults 0 1 +/dev/mapper/funtoo0-distfiles /var/distfiles xfs defaults 0 1 + +# ramdisks +tmpfs /tmp tmpfs defaults 0 0 + +# swap +/dev/mapper/funtoo0-swap none swap defaults 0 0 + +# binds +/tmp /var/tmp none rbind 0 0 +{% endhighlight %} + +##### /etc/localtime +The localtime comes next. This is to make sure your time is set correctly. An +incorrect time can cause issues such as secure connections failing. To set your +localtime, all you need to do is create a symlink. The file you need to symlink +to is stored in `/usr/share/zoneinfo`. The files are sorted by continent. As +someone who lives in the Netherlands, I'd use +`/usr/share/zoneinfo/Europe/Amsterdam`: + +{% highlight sh %} +ln -fs /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime +{% endhighlight %} + +It is important to also correctly set your hardware clock, in case it is off. +Check if your time and date are correct by invoking `date`. If these settings +are correct, you can skip towards the next heading. Otherwise, keep on reading +this bit. + +To set the correct time, you can use the `date` utility again. When invoked with +an argument in the form of `MMDDhhmmYYYY`, it will set the date and time instead +of check it. The following command would set the date to the first of October +2016, and the time to 17:29: + +{% highlight sh %} +date 011017292016 +{% endhighlight %} + +After you correctly set the date and time to whatever it currently is, sync it +to the hardware clock so it is correct across reboots: + +{% highlight sh %} +hwclock --systohc +{% endhighlight %} + +##### /etc/portage/make.conf +Another important part to configure is the `make.conf` file. This file contains +settings for portage and some options for compilers. This file can also be made +a directory. This way, you can split off your configs into multiple files for +easier maintainance. The files will be loaded alphabetically. The way you set it +up is completely up to you, though I would recommend removing the default +`/etc/portage/make.conf` and making it a directory instead. + +Once you have decided how to setup your make.conf, it is time to add some data +in the file(s). Following is a list of useful variables to set up, with a block +containing my own settings for it. You can copy these for yourself, or dig +aroudn some manpages to find out what you exactly want yourself. + +###### USE +`USE` holds global USE flags. These are used to configure your packages. You can +turn features on and off using these, and the ebuilds will configure the +packages to enable or disable these features. + +{% highlight sh %} +USE=" + ${USE} + alsa + gtk + gtkstyle + infinality + vim-syntax + zsh-completion + -pulseaudio + -systemd + -gnome + -kde +" +{% endhighlight %} + +###### FEATURES +The `FEATURES` variable allows enabling of various portage features. Mine are +setup to drop privileges so root is used as little as possible and to do as much +parallel as possible to speed up the process. Additionally, I use the `buildpkg` +feature to build binary packages for use on other systems. This can save you a +great deal of time if you have multiple systems running Funtoo. + +{% highlight sh %} +FEATURES=" + ${FEATURES} + buildpkg + network-sandbox + parallel-fetch + parallel-install + sandbox + userfetch + userpriv + usersandbox + usersync +" +{% endhighlight %} + +###### EMERGE_DEFAULT_OPTS +`EMERGE_DEFAULT_OPTS` can be used to add some flags to every emerge you invoke. +This way you can force emerge to always ask for confirmation. + +{% highlight sh %} +EMERGE_DEFAULT_OPTS=" + ${EMERGE_DEFAULT_OPTS} + --alert + --ask + --binpkg-changed-deps=y + --binpkg-respect-use=y + --keep-going + --tree + --usepkg + --verbose +" +{% endhighlight %} + +###### C/XXFLAGS +The `CFLAGS` and `CXXFLAGS` variables hold compiler-specific options. It is +**very** important to not use newlines in these two, as [they will break +`cmake`][bug-cmake]. Other than that, it is just a regular shell variable like +the others. + +{% highlight sh %} +CFLAGS="-O2 -pipe" +CXXFLAGS="-O2 -pipe" +{% endhighlight %} + +###### ACCEPT_LICENSE +This variable is not as important as the others. You can even opt to leave it +out completely. If, however, you wish to limit portage to only install free +software (free as in freedom, not gratis), you can set it to the same value as +me. Do note that if you use this, you will need to setup the +`/etc/portage/package.license` as well. + +{% highlight sh %} +ACCEPT_LICENSE=" + -* + @FREE +" +{% endhighlight %} + +###### MAKEOPTS +`MAKEOPTS` are the arguments passed to `make`. This can be used to instruct +`make` to use multiple threads when compiling software. The amount of threads +can be set with the `-j` flag. The general rule of thumb for this is to use +`$(($(nproc) + 1))`. + +{% highlight sh %} +MAKEOPTS=" + -j9 +" +{% endhighlight %} + +###### PKG/DISTDIR +The `PKGDIR` and `DISTDIR` variables set the location to store binary packages +after building, and the location to store distfiles. In order to use the +`/var/distfiles` and `/var/packages` partitions, these must be set. + +{% highlight sh %} +DISTDIR=/var/distfiles +PKGDIR=/var/packages +{% endhighlight %} + +##### /etc/portage/package.mask +Like the `make.conf` file, `package.mask` can be made a directory containing +seperate files. + +The `package.mask` file(s) allow you to "mask" packages, instructing portage to +ignore these. It can also let you mask certain versions of packages. This way +you can skip a broken version or stick to a certain version for whatever reason. +Since this tutorial uses ZFS, there is such a reason to do exactly that. + +ZFS requires a Linux at version 4.4 or lower. The latest kernel is much higher +than that, so it is necessary to mask newer kernel versions. This is a single +line of configuration, and as such can be done without a fancy editor. Simply +invoke the following magic: + +{% highlight sh %} +mkdir -p /etc/portage/package.mask +echo ">sys-kernel/gentoo-sources-4.4.6" > /etc/portage/package.mask/20-zfs.mask +{% endhighlight %} + +##### /etc/portage/package.license +This file can be setup as a directory too, just like `make.conf` and +`package.mask`. Using this file or directory you can add per-package license +exceptions. This is therefore only needed if you setup a strict license limit. +The kernel comes with some sources under the `freedist` license, which is not +part of `@FREE`. As such, if you want to install kernel sources you will have to +make an exception for this license on this package. + +{% highlight sh %} +mkdir -p /etc/portage/package.license +echo "sys-kernel/gentoo-sources freedist" > /etc/portage/package.license/20-freedist.license +{% endhighlight %} + +##### /etc/conf.d/hostname +As one of the last files to setup, the hostname should be set in +`/etc/conf.d/hostname`. The `hostname` variable in this file should be set to +the hostname of the machine. You can pick any name you like, but should be +unique across your network. + +#### Preparing your first kernel +Every system needs a kernel, a piece of software to interface with the hardware. +Funtoo, like every GNU+Linux distribution, uses the Linux kernel for this task. + +For this task, you will first need to decide on a source set to use. All source +sets share the same base, but they have different patches applied. It is +recommended to use `sys-kernel/gentoo-sources`. If this isn't bleeding edge +enough, you can use `sys-kernel/git-sources` instead. If you just want the +latest official kernel without the gentoo patchset, pick +`sys-kernel/vanilla-sources`. No matter which source set you use, the +compilation and installation process remains the same. + +Install whichever source set you want to use, this guide will use +`sys-kernel/gentoo-sources`. In order to save some yes-pressing later on, the +`emerge` command here will install some additional packages which are needed for +the system to function properly. + +{% highlight sh %} +emerge boot-update cryptsetup lvm2 gentoo-sources +genkernel --menuconfig --lvm --luks all +{% endhighlight %} + +The `genkernel` command will run the kernel menuconfig utility. If you have +exotic hardware that needs special support, this is the place to enable it. The +defaults are sane for most systems. If you have nothing to configure here, just +exit the menuconfig and let `genkernel` build a custom kernel and initramfs for +you. As the guide uses LVM and LUKS, you will need to have support for these +things in your kernel. You will need to enable the following options at the +very least: + +{% highlight plain %} +General setup ---> + [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support +{% endhighlight %} + +{% highlight plain %} +Device Drivers ---> + Generic Driver Options ---> + [*] Maintain a devtmpfs filesystem to mount at /dev +{% endhighlight %} + +{% highlight plain %} +Device Drivers ---> + [*] Multiple devices driver support ---> + <*>Device Mapper Support + <*> Crypt target support +{% endhighlight %} + +{% highlight plain %} +Cryptographic API ---> + <*> XTS support + -*-AES cipher algorithms +{% endhighlight %} + +#### Setup ZFS +The kernel is now installed at `/boot`, and all the required parts to build +custom kernel modules are available. This means it is now possible to build the +ZFS modules. + +First install the kernel module here. Since the live kernel does not have the +zfs modules from the chroot, you must create the pool and the volumes after the +first reboot. + +{% highlight sh %} +emerge zfs +{% endhighlight %} + +Once it has been compiled, you can add the ZFS services to start up by default. +This will load the kernel module for you and all additional services that make +ZFS perform its job well. + +{% highlight sh %} +rc-update add zfs-import boot +rc-update add zfs-mount boot +rc-update add zfs-share default +rc-update add zfs-zed default +{% endhighlight %} + +#### Installing a bootloader +Before building your kernel, `boot-update` was installed. This pulls in +[`grub`][wikipedia-grub], the recommended bootloader for Funtoo. It doesn't +require a lot of configuration thanks to the `boot-update` script, which will +configure `grub` for you. + +Before running the script, there's one place to update as this setup uses `luks` +and `lvm`. + +Open up `/etc/boot.conf` in your favourite editor and let the file display +something like this: + +{% highlight plain %} +boot { + generate grub + default "Funtoo GNU+Linux" + timeout 3 +} + +"Funtoo GNU+Linux" { + kernel kernel[-v] + initrd initramfs[-v] + params += crypt_root=/dev/sda2 real_root=/dev/mapper/funtoo0-root rootfstype=xfs dolvm +} +{% endhighlight %} + +Now that `boot-update` is configured, install `grub` as an UEFI bootloader and +generate the configs for it using `boot-update`. You should make sure the +`grub` directory exists in `/boot` as well. + +{% highlight sh %} +mkdir -p /boot/grub +grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id="Funtoo GNU+Linux" --recheck /dev/sda +boot-update +{% endhighlight %} + +#### Set your system profile +Your system is now ready to boot and use. However, some things are still not +configured. These can in some cases be configured after rebooting, but it is +recommended to fix it all up now. The first part is setting your system profile. + +For a full list of settings, check `epro list`. Maybe you want to use this +system as something other than a workstation, or want to enable the `gnome` +mix-in. + +To get the same profile settings as I use for my work environments, run the +following: + +{% highlight sh %} +epro flavor workstation +epro mix-ins +no-systemd +{% endhighlight %} + +#### Running the first full system update +The stage 3 tarball may have been the latest, but it might still have some +slightly outdated packages. In addition, now that your system profile is set up, +some applications may be configured to have different feature sets enabled. To +make sure everything is in the best possible state, it is recommended to run a +full system update now. Since some of our options are already set as +`EMERGE_DEFAULT_OPTS`, this is as simple as + +{% highlight sh %} +emerge -uDN @world +{% endhighlight %} + +#### Installing supporting software +This is software you will more than likely need on any standard system. If +you're an advanced user you can decide to skip this and make your own choices, +otherwise it is recommended to install this software as well. + +{% highlight sh %} +emerge connman sudo vim linux-firmware +{% endhighlight %} + +#### Configuring supporting software +Some of the supporting software has to be turned on explicitly or have a +configuration file tweaked. If you opted to not use a given recommended package, +you can skip the section with the same name. + +##### connman +[`connman`][wikipedia-connman] is a simple **conn**ection **man**ager. It's +lightweight, fast and does its job pretty well. To enable this service at boot, +run + +{% highlight sh %} +rc-update add connman default +{% endhighlight %} + +If you want to setup wireless connection authentication credentials, read up on +`man connman-service.conf`. + +##### sudo +The [`sudo`][wikipedia-sudo] utility allows certain users, based on their +username or groups they belong to, access to privileged commands. It can also be +used to run a command as a different user. The most basic setup allows people +from the `wheel` group to execute commands normally reserved for `root`. + +Because sudo is a critical utility, it comes with its own editor that basically +just wraps your preferred editor in a script that will complain if the +configuration is wrong. To use this tool, invoke + +{% highlight sh %} +visudo +{% endhighlight %} + +Scroll to the line which contains `# %wheel ALL=(ALL) ALL`, and remove the `# `. + +#### Set passwords +We probably want to be able to login to the system as well. By default, users +without passwords are disabled, so you'll need to set a password for the users +you want to be able to use: + +{% highlight sh %} +passwd root +{% endhighlight %} + +If you used a different username than `tyil`, be sure to change it here as well. + +### First boot +Installation is now finished, so it is time to boot into your new Funtoo system. +First you should cleanly unmount all partitions and then issue a reboot: + +{% highlight sh %} +exit +cd +umount -lR /mnt/gentoo +reboot +{% endhighlight %} + +If you set your UEFI to favour the USB system over the standard drive in the +booting order, be sure to either change this back, or simply remove the USB +device. + +### First boot configurations +After your system has succesfully booted, login as root using the password you +set using `passwd` before rebooting. + +#### ZFS +Now you can finally setup the ZFS partition. Issue the following commands to +create a pool and a subvolume for `/home`: + +{% highlight sh %} +zpool create funtooz /dev/sda +zfs create -o mountpoint=/home funtooz/home +{% endhighlight %} + +#### Create a user +Create a user for yourself on the system, as you should not perform regular +usage as root. You can use any other value for `tyil` if you so desire: + +{% highlight sh %} +useradd -m -g users -G wheel tyil +passwd tyil +{% endhighlight %} + +The `-G wheel` part is optional, but recommended if you wish to use this account +for administrative tasks. This option adds the user to the `wheel` group, which +will allow the user to execute root commands using `sudo`. + +#### Login +Now you have a non-privileged user to login to. Log out of the root user by +running `exit`. Next, log in on your normal user account. + +## What's next +Now you have a working Funtoo installation. Next steps would be installing all +the software you wish to use and configuring it to your liking. I would greatly +advise looking at other people's configurations and publishing your +configurations as well. These configuration collections are often called +*dotfiles*. Mine can be found [on c.darenet.org][dotfiles]. + +If this is your first time using Funtoo as your distro of choice, I would +recommend looking through [Funtoo (GNU+)Linux First Steps][funtoo-first] on the +official Funtoo wiki. + +If you need assistance on maintainance, you can always drop by in `#sqt` on +[Gratisnode][freenode]. + +[bug-cmake]: https://bugs.gentoo.org/show_bug.cgi?id=500034#c6 +[dotfiles]: https://c.darenet.org/tyil/dotfiles-gohan +[funtoo-first]: http://www.funtoo.org/Funtoo_Linux_First_Steps +[freenode]: https://freenode.net +[funtoo-build]: http://build.funtoo.org/ +[funtoo]: http://build.funtoo.org/distfiles/sysresccd/systemrescuecd-x86-4.7.1.iso +[osuosl]: http://ftp.osuosl.org/pub/funtoo/distfiles/sysresccd/systemrescuecd-x86-4.7.1.iso +[sysrescuecd]: http://www.system-rescue-cd.org/SystemRescueCd_Homepage +[tyil]: http://tyil.work +[wikipedia-chroot]: https://en.wikipedia.org/wiki/Chroot +[wikipedia-connman]: https://en.wikipedia.org/wiki/ConnMan +[wikipedia-cryptsetup]: https://en.wikipedia.org/wiki/Dm-crypt#cryptsetup +[wikipedia-ed]: https://en.wikipedia.org/wiki/Ed_(text_editor) +[wikipedia-git]: https://en.wikipedia.org/wiki/Git +[wikipedia-grub]: https://en.wikipedia.org/wiki/GNU_GRUB +[wikipedia-luks]: https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup +[wikipedia-lvm]: https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux) +[wikipedia-nano]: https://en.wikipedia.org/wiki/GNU_nano +[wikipedia-sudo]: https://en.wikipedia.org/wiki/Sudo +[wikipedia-vi]: https://en.wikipedia.org/wiki/Vi +[wikipedia-zfs]: https://en.wikipedia.org/wiki/ZFS + diff --git a/_posts/2016-10-25-setup-a-vpn-with-cjdns.md b/_posts/2016-10-25-setup-a-vpn-with-cjdns.md new file mode 100644 index 0000000..d97a42f --- /dev/null +++ b/_posts/2016-10-25-setup-a-vpn-with-cjdns.md @@ -0,0 +1,212 @@ +--- +title: Setup a VPN with cjdns +date: 2016-10-25 08:00:34 +tags: Tutorial Cjdns Installation VPN +layout: post +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# Setup VPN with cjdns +In this tutorial I will outline a simple setup for a [VPN][vpn] using +[`cjdns`][cjdns]. Cjdns will allow you to setup a secure mesh vpn which uses +IPv6 internally. + +## Requirements +For this tutorial, I have used two client machines, both running Funtoo. A +FreeBSD 11 server is used as a global connection point. + +You are ofcourse able to use any other OS or distro supported by cjdns, but you +may have to update some steps to work on your environment in that case. + +## Installation of the server +### Dependencies +Before you can begin, we need some dependencies. There's only two of those, and +they are available via `pkg` to make it even easier. Install them as follows: + +{% highlight sh %} +pkg install gmake node +{% endhighlight %} + +### Compiling +Next up is getting the cjdns sources and compile these, as cjdns is not +available as a prebuilt package: + +{% highlight sh %} +mkdir -p ~/.local/src +cd $_ +git clone https://github.com/cjdelisle/cjdns.git cjdns +cd $_ +./do +{% endhighlight %} + +To make the compiled binary available system-wide so we can use it with a +system service, copy it to `/usr/local/bin` and rehash to make it available as +a direct command: + +{% highlight sh %} +cp cjdroute /usr/local/bin/. +hash -r +{% endhighlight %} + +### Configuring +Cjdns provides a flag to generate the initial configuration. This will provide +you with some sane defaults where only a couple of small changes are needed to +make it work properly. Generate these defaults with `--genconf`: + +{% highlight sh %} +(umask 177 && cjdroute --genconf > /usr/local/etc/cjdroute.conf) +{% endhighlight %} + +The umask will make all following commands write files using `600` permissions. +This makes sure the config file is not readable by people who shouldn't be able +to read it. Be sure to check wether the owner of the file is `root`! + +Now you can start actually configuring the node to allow incoming connections. +You have to find the `authorizedPasswords` array in the `cjdroute.conf` file +and remove the contents of it. Then you can add your own machines in it. This +guide follows the assumption of two clients, so the config for two clients will +be shown here. You can add more clients if you wish, ofcourse. + +{% highlight json %} +"authorizedPasswords": +[ + {"password": "aeQu6pa4Vuecai3iebah7ogeiShaeDaepha6Mae1yooThoF0oa0Eetha9oox", "user": "client_1"}, + {"password": "aiweequuthohkahx4tahLohPiezee9OhweiShoNeephe0iekai2jo9Toorah", "user": "client_2"}, +] +{% endhighlight %} + +If you need to generate a password, you can make use of the tool `pwgen`, +available at your local package manager. You can then generate new passwords by +running `pwgen 60 -1`. Change the `60` around if you want passwords of a +different size. + +### Adding a startup service +rcinit has deceptively easy scripts to make applications available as services. +This in turn allows you to enable a service at startup. This way you can make +sure cjdns starts whenever the server boots. You can copy the following +contents directly into `/usr/local/etc/rc.d/cjdroute`: + +{% highlight sh %} +#! /bin/sh + +# PROVIDE: cjdroute +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable cjdroute: +# +#cjdroute_enable="YES" + +. /etc/rc.subr + +name="cjdroute" +rcvar="cjdroute_enable" + +load_rc_config $name + +: ${cjdroute_config:=/usr/local/etc/cjdroute.conf} + +command="/usr/local/bin/cjdroute" +command_args=" < ${cjdroute_config}" + +run_rc_command "$1" +{% endhighlight %} + +Afterwards, you must enable the service in `/etc/rc.conf.local` like follows: + +{% highlight sh %} +echo 'cjdroute_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +## Installation of the clients +### Dependencies +The dependencies are still on `gmake` and `node`, so simply install those on +your clients. This guide assumes using Funtoo for the clients, so installation +would go as follows: + +{% highlight sh %} +emerge gmake nodejs +{% endhighlight %} + +### Compiling +Compilation is the same as for the server, so check back there for more +information if you have already forgotten. + +### Configuring +Generating the base configuration is again done using `cjdroute --genconf`, +just like on the server. On Funtoo, config files generally reside in `/etc` +instead of `/usr/local/etc`, so you should set the filepath you write the +configuration to accordingly: + +{% highlight sh %} +cjdroute --genconf > /etc/cjdroute.conf +{% endhighlight %} + +Setting up the connections differs as well, as the clients are going to make an +outbound connection to the server, which is configured to accept inbound +connections. + +You should still clean the `authorizedPasswords` array, as it comes with a +default entry that is uncommented. + +Now you can setup outbound connections on the clients. You set these up in the +`connectTo` block of `cjdroute.conf`. For this example, the IP 192.168.1.1 is +used to denote the server IP. Unsurprisingly, you should change this to your +server's actual IP. You can find the `publicKey` value at the top of your +server's `cjdroute.conf` file. + +On client 1, put the following in your `cjdroute.conf`: + +{% highlight json %} +"connectTo": +{ + "192.168.1.1:9416": + { + "login": "client_1", + "password": "aeQu6pa4Vuecai3iebah7ogeiShaeDaepha6Mae1yooThoF0oa0Eetha9oox", + "publicKey": "thisIsJustForAnExampleDoNotUseThisInYourConfFile_1.k" + } +} +{% endhighlight %} + +On client 2: + +{% highlight json %} +"connectTo": +{ + "192.168.1.1:9416": + { + "login": "client_2", + "password": "aiweequuthohkahx4tahLohPiezee9OhweiShoNeephe0iekai2jo9Toorah", + "publicKey": "thisIsJustForAnExampleDoNotUseThisInYourConfFile_1.k" + } +} +{% endhighlight %} + +That is all for configuring the nodes. + +### Adding a startup service +You probably want cjdroute to run at system startup so you can immediatly use +your VPN. For openrc based systems, such as Funtoo, cjdns comes with a ready to +use service script. To make this available to your system, copy it over to the +right directory: + +{% highlight sh %} +cp ~/.local/src/cjdns/contrib/openrc/cjdns /etc/init.d/cjdroute +{% endhighlight %} + +Now add the service to system startup and start the service: + +{% highlight sh %} +rc-update add cjdroute default +rc-service cjdroute start +{% endhighlight %} + +That should be sufficient to get cjdns up and running for an encrypted VPN. You +can find the IPs of each of your systems at the top of your `cjdroute.conf` +files, in the `ipv6` attribute. + +[cjdns]: https://github.com/cjdelisle/cjdns +[vpn]: https://en.wikipedia.org/wiki/Virtual_private_network + diff --git a/_posts/2016-10-25-setup-nginx-with-lets-encrypt-ssl.md b/_posts/2016-10-25-setup-nginx-with-lets-encrypt-ssl.md new file mode 100644 index 0000000..62299a1 --- /dev/null +++ b/_posts/2016-10-25-setup-nginx-with-lets-encrypt-ssl.md @@ -0,0 +1,229 @@ +--- +title: Setup nginx with Let's Encrypt SSL +date: 2016-10-25 08:00:34 +tags: Tutorial Installation LetsEncrypt Nginx SSL Encryption +layout: post +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# Setup nginx with Let's Encrypt SSL +This is a small tutorial to setup nginx with Let's Encrypt on a FreeBSD server +to host a static site. + +## Install required software +First you have to install all the packages we need in order to get this server +going: + +{% highlight sh %} +pkg install nginx py27-certbot +{% endhighlight %} + +## Configure nginx +Next is nginx. To make life easier, you should configure nginx to read all +configuration files from another directory. This allows you to store all your sites in +separate configurations in a separate directory. Such a setup is a regular site on +nginx installations on GNU+Linux distributions, but not default on FreeBSD. + +Open up `/usr/local/etc/nginx/nginx.conf` and make the contents of the `http` +block look a as follows: + +{% highlight nginx %} +http { + include mime.types; + default_type application/octet-stream; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + # default paths + index index.html; + + # disable gzip - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=773332 + gzip off; + + # default ssl settings + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + ssl_ciphers HIGH:!aNULL:!MD5:!AES128:!CAMELLIA128; + ssl_protocols TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_dhparam /usr/local/etc/ssl/dhparam.pem; + + # default logs + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/acces.log; + + # default server + server { + listen 80; + server_name localhost; + + location / { + root /usr/local/www/nginx; + index index.html index.htm; + } + + error_page 404 /404.html; + error_page 500 502 503 504 /50x.html; + + location = /50x.html { + root /usr/local/www/nginx-dist; + } + } + + # include site-specific configs + include sites/*.conf; +} +{% endhighlight %} + +This sets default ssl settings for all server blocks that enable ssl. Note that +these are settings I use, and are in no way guaranteed to be perfect. I did some +minor research on these settings to get an acceptable rating on +[SSL Labs][ssllabs]. However, security is not standing still, and there is a +decent chance that my settings will become outdated. If you have better settings +that result in a safer setup, please [contact me][contact]. + +### Setup HTTP +Due to the way `certbot` works, you need a functioning web server. Since there +is no usable cert yet, this means hosting a HTTP version first. The tutorial +assumes a static HTML website to be hosted, so the configuration is pretty +easy. + +Put the following in `/usr/local/etc/nginx/sites/domain.conf`: + +{% highlight nginx %} +# static HTTP +server { + # listeners + listen 80; + server_name domain.tld www.domain.tld; + + # site path + root /srv/www/domain/_site; + + # / handler + location / { + try_files $uri $uri/ =404; + } + + # logs + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; +} +{% endhighlight %} + +If your site's sources do not reside in `/srv/www/domain/_site`, change the +path accordingly. This guide will continue using this path for all examples, so +be sure to modify this where needed. In the same vein, the domain `domain.tld` +will be used. Modify this to your own domain. + +### Start nginx +Nginx is now configured to host a single site over HTTP. Now is the time to enable +the nginx service. Execute the following: + +{% highlight sh %} +echo 'nginx_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +This will enable nginx as a system service. On reboots, it will be started +automatically. You can also start it up without rebooting by running the +following: + +{% highlight sh %} +service nginx start +{% endhighlight %} + +## Configure Let's Encrypt +Nginx is now running as your web server on port 80. Now you can request Let's +Encrypt certificates using `certbot`. You can do so as follows: + +{% highlight sh %} +certbot certonly --webroot -w /srv/www/domain/_site -d domain.tld -d www.domain.tld +{% endhighlight %} + +In case you want to add any sub domains, simply add more `-d sub.domain.tld` +arguments at the end. If the DNS entries for the domains resolve properly, and +no unexpected errors occur on the Let's Encrypt side, you should see a message +congratulating you with your new certs. + +If your domains do not resolve correctly, `certbot` will complain about this. +You will have to resolve your DNS issues before attempting again. + +If `certbot` complains about an unexpected error on their side, wait a couple +minutes and retry the command. It should work, eventually. + +Once `certbot` has ran without errors, the required files should be available +in `/usr/local/etc/letsencrypt/live/domain.tld`. + +## Configure nginx with SSL +The certificate has been issued and base nginx is running. Now is the time to +re-configure your site on nginx to host the HTTPS version of your site instead. +Open up `/usr/local/etc/nginx/sites/domain.conf` again, and make the contents +look like the following: + +{% highlight nginx %} +# redirect HTTPS +server { + # listeners + listen 80; + server_name domain.tld *.domain.tld; + + # redirects + return 301 https://$host$request_uri; +} + +# static HTTPS +server { + # listeners + listen 443 ssl; + server_name domain.tld www.domain.tld; + + # site path + root /srv/www/domain/_site; + + # / handler + location / { + try_files $uri $uri/ =404; + } + + # enable HSTS + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; + + # keys + ssl_certificate /usr/local/etc/letsencrypt/live/domain.tld/fullchain.pem; + ssl_certificate_key /usr/local/etc/letsencrypt/live/domain.tld/privkey.pem; +} +{% endhighlight %} + +Do not forget to update all the paths to match your setup! + +As a final step, you should generate the dhparam file. This is to avoid the +issues as described on [Weak DH][weakdh]. + +{% highlight sh %} +openssl gendh -out /usr/local/etc/ssl/dhparam.pem 4096 +{% endhighlight %} + +Be aware that this step can take a **very** long time. On the test machine I +used to test this tutorial, with 1 core and 1 GB ram, it took nearly 1 hour to +generate this file. + +### Reload nginx +The final step is to reload the nginx configuration so it hosts the SSL version +of your site, and redirects the HTTP version to the HTTPS version. To do this, +simply run + +{% highlight sh %} +service nginx reload +{% endhighlight %} + +That should be all to get your site working with HTTP redirecting to HTTPS, and +HTTPS running using a gratis Let's Encrypt certificate. + +[contact]: https://www.tyil.work/ +[ssllabs]: https://www.ssllabs.com/ssltest/analyze.html?d=tyil.work&latest +[weakdh]: https://weakdh.org/ + diff --git a/_posts/2016-10-31-freebsd-mailserver-part-1-preparations.md b/_posts/2016-10-31-freebsd-mailserver-part-1-preparations.md new file mode 100644 index 0000000..96ba62d --- /dev/null +++ b/_posts/2016-10-31-freebsd-mailserver-part-1-preparations.md @@ -0,0 +1,141 @@ +--- +title: "FreeBSD email server - Part 1: Preparations" +date: 2016-10-31 07:57:50 +tags: Tutorial FreeBSD Email Installation +layout: post +authors: + - ["Patrick Spek", "https://www.tyil.work"] +--- + +# FreeBSD email server - Part 1: Preparations +This tutorial is devised into multiple chapters to make it more manageable, and +to be able to better explain why certain parts are needed. + +The tutorial is created out of experience setting up my own email server. I have +read through quite a lot of documentation so you do not have to. Nonetheless, I +would recommend doing so. Email business is a tricky one, with a lot of moving +parts that have to fit into each other. Knowing how exactly each part works will +greatly help understanding why they are needed in a proper email server. +Besides that, it will make your life a lot more enjoyable if you want to tweak +some things after this tutorial. + +To kick off, some preparations should be done before you start on setting up +your own email server. + +## DNS setup +Some DNS setup is required for mail. Most importantly, the MX records of a +domain. Be sure you have a domain available, otherwise, get one. There are +plenty of registrars and the price is pretty low for most domains. If you want +to look hip, get a `.email` TLD for your email server. + +For the DNS records themselves, make sure you have an `A` record pointing to +the server IP you're going to use. If you have an IPv6 address, set up an +`AAAA` record as well. Mail uses the `MX` DNS records. Make one with the value +`10 @`. If you have multiple servers, you can make MX records for these as +well, but replace the `10` with a higher value each time (`20`, `30`, etc). +These will be used as fallback, in case the server with pointed to by the `10` +record is unavailable. + +## PostgreSQL +Next up you will have to install and configure [PostgreSQL][postgres]. Although +using a database is not required, this tutorial will make use of one. Using a +database makes administration easier and allows you to add a pretty basic web +interface for this task. + +### Installation +Since the tutorial uses FreeBSD 11, you can install PostgreSQL easily by running + +{% highlight sh %} +pkg install postgresql96-server +{% endhighlight %} + +### Starting up +In order to start Postfix, you should enable the system service for it. This +way, `service` can be used to easily manage it. In addition, it will start +automatically on boot. + +{% highlight sh %} +echo 'postgresql_enable="YES"' >> /etc/rc.conf.local +service postgresql start +{% endhighlight %} + +### Database initialization +Since PostgreSQL is a little different than the more popular [MySQL][mysql], I +will guide you through setting up the database as well. To begin, switch user +to `postgres`, which is the default administrative user for PostgreSQL. Then +simply open up the PostgreSQL CLI. + +{% highlight sh %} +su postgres +psql +{% endhighlight %} + +Once you are logged in to PostgreSQL, create a new user which will hold +ownership of the database and make a database for this user. + +{% highlight sql %} +CREATE USER postfix WITH PASSWORD 'incredibly-secret!'; +CREATE DATABASE mail WITH OWNER postfix; +{% endhighlight %} + +Once this is done, create the tables which will hold some of our configuration +data. + +#### domains +{% highlight sql %} +CREATE TABLE domains ( + name VARCHAR(255) NOT NULL, + PRIMARY KEY (name) +); +{% endhighlight %} + +#### users +{% highlight sql %} +CREATE TABLE users ( + local VARCHAR(64) NOT NULL, + domain VARCHAR(255) NOT NULL, + password VARCHAR(128) NOT NULL, + PRIMARY KEY (local, domain), + FOREIGN KEY (domain) REFERENCES domains(name) ON DELETE CASCADE +); +{% endhighlight %} + +#### aliases +{% highlight sql %} +CREATE TABLE aliases ( + domain VARCHAR(255), + origin VARCHAR(256), + destination VARCHAR(256), + PRIMARY KEY (origin, destination), + FOREIGN KEY (domain) REFERENCES domains(name) ON DELETE CASCADE +); +{% endhighlight %} + +## Let's Encrypt +### Installation +Installing the [Let's Encrypt][letsencrypt] client is just as straightforward +as the PostgreSQL database, using `pkg`. + +{% highlight sh %} +pkg install py27-certbot +{% endhighlight %} + +### Getting a certificate +Requesting a certificate requires your DNS entries to properly resolve. If they +do not resolve yet, Let's Encrypt will bother you with errors. If they do +resolve correctly, use `certbot` to get your certificate. + +{% highlight sh %} +certbot certonly --standalone -d domain.tld +{% endhighlight %} + +## Conclusion +This should be everything required to get started on setting up your own email +server. Continue to [part 2][part-2] of this series to start setting up +Postfix. + +[freebsd]: https://www.freebsd.org/ +[letsencrypt]: https://letsencrypt.org/ +[mysql]: https://www.mysql.com/ +[part-2]: https://www.tyil.work/tutorials/freebsd-mailserver-part-2-mailing-with-postfix/ +[postgres]: https://www.postgresql.org/ diff --git a/_posts/2016-10-31-freebsd-mailserver-part-2-mailing-with-postfix.md b/_posts/2016-10-31-freebsd-mailserver-part-2-mailing-with-postfix.md new file mode 100644 index 0000000..17e5b49 --- /dev/null +++ b/_posts/2016-10-31-freebsd-mailserver-part-2-mailing-with-postfix.md @@ -0,0 +1,316 @@ +--- +title: "FreeBSD email server - Part 2: Mailing with Postfix" +date: 2016-10-31 07:57:50 +tags: Tutorial FreeBSD Email Installation +layout: post +authors: + - ["Patrick Spek", "https://www.tyil.work"] +--- + +# FreeBSD email server - Part 2: Mailing with Postfix +Welcome to the second part of my FreeBSD email server series. In this series, I +will guide you through setting up your own email service. Be sure to done the +preparations from [part 1][part-1] of this series. + +This part will guide you through setting up email service on your machine using +[Postfix][postfix]. Basic installation is pretty straightforward, but there is +a lot to configure. If you are not sure what some configuration options do, +please read up on them. There is a lot to do wrong with a mail server, and +doing things wrong will likely get you on a blacklist which will make other +servers stop processing the mail you are trying to send out. + +Setting up Postfix is one of the harder parts of configuring a mail server. If +you have questions after reading the full guide, please find me on IRC. You can +find details on how to do so on [my homepage][home]. + +## Installing Postfix +Installation procedures on FreeBSD are pretty straightforward. Unlike `certbot` +from the previous part, we will need to compile Postfix from source in order to +use PostgreSQL as a database back-end. Thanks to FreeBSD's +[ports][freebsd-ports], this is not difficult either. If this is your first +port to compile, you probably need to get the ports tree first. You can +download and extract this using the following command. + +{% highlight sh %} +portsnap fetch extract +{% endhighlight %} + +Once that has finished running, go into the directory containing the build +instructions for Postfix, and start the installation process. + +{% highlight sh %} +cd /usr/ports/mail/postfix +make configure install +{% endhighlight %} + +This will open a pop up with a number of options you can enable or disable. The +enabled defaults are fine, but you will have to enable the `PGSQL` option. This +will allow you to use the configuration tables created in part 1. + +## Enabling Postfix +Enable the Postfix service for rcinit. This allows you to use `service postfix +start` once configuration is done, and will auto start the service on system +boot. In addition, the default mailer on FreeBSD, [sendmail][sendmail] should +be disabled so nothing is in Postfix's way when trying to deal with processing +email traffic. + +{% highlight sh %} +# disable the default sendmail system +echo 'daily_clean_hoststat_enable="NO"' >> /etc/periodic.conf.local +echo 'daily_status_mail_rejects_enable="NO"' >> /etc/periodic.conf.local +echo 'daily_status_include_submit_mailq="NO"' >> /etc/periodic.conf.local +echo 'daily_submit_queuerun="NO"' >> /etc/periodic.conf.local +echo 'sendmail_enable="NONE"' >> /etc/rc.conf.local + +# enable postfix +echo 'postfix_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +## Configuring Postfix +There is a ton to configure for Postfix. This configuration happens in two +files, `main.cf` and `master.cf`. Additionally, as some data is in the +PostgreSQL database, three files with information on how to query for this +information are needed. All of these files are in `/usr/local/etc/postfix`. + +The guide has a comment line for most blocks. It is advised that **if** you +decide to just copy and paste the contents, you copy that along so you have +some sort of indication of what is where. This could help you out if you ever +need to change anything later on. + +### main.cf +#### Compatibility +The configuration file starts off by setting the compatibility level. If +postfix updates the configuration scheme and deprecates certain options, you +will be notified of this in the logs. + +{% highlight ini %} +# compatibility +compatibility_level = 2 +{% endhighlight %} + +#### Directory paths +These options indicate where Postfix will look and keep certain files required +for correct operation. + +{% highlight ini %} +# directory paths +queue_directory = /var/spool/postfix +command_directory = /usr/local/sbin +daemon_directory = /usr/local/libexec/postfix +data_directory = /var/db/postfix +{% endhighlight %} + +#### Domain configuration +The domain configuration instruct the server of the domain(s) it should serve +for. Use your FQDN without sub domains for `mydomain`. You can use a sub domain +for `myhostname`, but you are not required to. The most common setting is +using a `mail` sub domain for all mail related activities, which would +result in something like this. + +{% highlight ini %} +# domain configuration +myhostname = mail.domain.tld +mydomain = domain.tld +myorigin = $mydomain +{% endhighlight %} + +#### Listening directives +All internet devices it should listen on, and all domains this server should +consider itself the endpoint for, should be listed here. The defaults in the +example block are good enough, as we put some of our data in the PostgreSQL +database instead. + +{% highlight ini %} +# listening directives +inet_interfaces = all +mydestination = $myhostname, localhost.$mydomain, localhost +{% endhighlight %} + +#### Reject unknown recipients +How to deal with messages sent to an email address whose domain points to your +server's address, but have no actual mailbox. A code of `550` means to inform +the remote server that delivery is not possible and will not be possible. This +should stop the remote server from trying it again. + +{% highlight ini %} +# reject unknown recipients +unknown_local_recipient_reject_code = 550 +{% endhighlight %} + +#### Trust +{% highlight ini %} +# trust +mynetworks_style = host +{% endhighlight %} + +#### Address extensions +This block is optional. It allows you to use email address extensions. These +are addresses with an additional character in them that will drop the email in +the non extended address' mailbox, but allows you to quickly filter on them as +the sent-to address contains the extension. + +{% highlight ini %} +# address extensions +recipient_delimiter = + +{% endhighlight %} + +#### Virtual domain directives +This part is where things get important. Virtual domains allow you to handle +mail for a large number of domains that are different from the actual server's +domain. This is where the database configuration comes in to play. It is +important to note the `static:125` values. The `125` should map to the `UID` of +the `postfix` user account on your system. + +{% highlight ini %} +# virtual domain directives +virtual_mailbox_base = /srv/mail +virtual_mailbox_domains = pgsql:/usr/local/etc/postfix/pgsql-virtual-domains.cf +virtual_mailbox_maps = pgsql:/usr/local/etc/postfix/pgsql-virtual-users.cf +virtual_alias_maps = pgsql:/usr/local/etc/postfix/pgsql-virtual-aliases.cf +virtual_uid_maps = static:125 +virtual_gid_maps = static:125 +virtual_transport = lmtp:unix:private/dovecot-lmtp +{% endhighlight %} + +#### TLS setup +The TLS setup configures your server to use secure connections. The keys used +here have been generated in the previous part of this series. + +{% highlight ini %} +# TLS setup +smtpd_tls_cert_file = /usr/local/etc/letsencrypt/live/domain.tld/fullchain.pem +smtpd_tls_key_file = /usr/local/etc/letsencrypt/live/domain.tld/privkey.pem +smtpd_use_tls = yes +smtpd_tls_auth_only = yes +{% endhighlight %} + +#### SASL setup +SASL deals with the authentication of the users to your email server. + +{% highlight ini %} +# SASL setup +smtpd_sasl_type = dovecot +smtpd_sasl_path = private/auth +smtpd_sasl_auth_enable = yes +smtpd_recipient_restrictions = + permit_sasl_authenticated, + permit_mynetworks, + reject_unauth_destination +smtpd_relay_restrictions = + permit_sasl_authenticated, + permit_mynetworks, + reject_unauth_destination +{% endhighlight %} + +#### Debugging +The debugging options are generally useful in case things break. If you have +little traffic, you could leave them on forever in case you want to debug +something later on. Once your server is working as intended, you should turn +these options off. The postfix logs get pretty big in a short amount of time. + +{% highlight ini %} +# debugging +debug_peer_level = 2 +debugger_command = + PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/binary + ddd $daemon_directory/$process_name $process_id & sleep 5 +{% endhighlight %} + +#### Installation time defaults +These options should not be touched, but are very important to have for your +server. + +{% highlight ini %} +# install-time defaults +sendmail_path = /usr/local/sbin/sendmail +newaliases_path = /usr/local/bin/newaliases +mailq_path = /usr/local/bin/mailq +setgid_group = maildrop +html_directory = /usr/local/share/doc/postfix +manpage_directory = /usr/local/man +sample_directory = /usr/local/etc/postfix +readme_directory = /usr/local/share/doc/postfix +inet_protocols = ipv4 +meta_directory = /usr/local/libexec/postfix +shlib_directory = /usr/local/lib/postfix +{% endhighlight %} + +### master.cf +For the `master.cf` file, you can use the following configuration block. + +{% highlight cfg %} +submission inet n - n - - smtpd + -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o smtpd_sasl_auth_enable=yes + -o smtpd_reject_unlisted_recipient=no + -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING +pickup unix n - n 60 1 pickup +cleanup unix n - n - 0 cleanup +qmgr unix n - n 300 1 qmgr +tlsmgr unix - - n 1000? 1 tlsmgr +rewrite unix - - n - - trivial-rewrite +bounce unix - - n - 0 bounce +defer unix - - n - 0 bounce +trace unix - - n - 0 bounce +verify unix - - n - 1 verify +flush unix n - n 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - n - - smtp +relay unix - - n - - smtp +showq unix n - n - - showq +error unix - - n - - error +retry unix - - n - - error +discard unix - - n - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - n - - lmtp +anvil unix - - n - 1 anvil +scache unix - - n - 1 scache +{% endhighlight %} + +### SQL query files +The following three configuration files deal with the SQL query files to make +Postfix able of getting some of its configuration from a database. You +obviously have to change the first 4 directives to match your database +authentication credentials. + +#### pgsql-virtual-domains.cf +{% highlight ini %} +user = postgres +password = incredibly-secret! +hosts = 127.1 +dbname = mail +query = SELECT 1 FROM domains WHERE name='%s'; +{% endhighlight %} + +#### pgsql-virtual-users.cf +{% highlight ini %} +user = postgres +password = incredibly-secret! +hosts = 127.1 +dbname = mail +query = SELECT 1 FROM users WHERE local='%u' AND domain='%d'; +{% endhighlight %} + +#### pgsql-virtual-aliases.cf +{% highlight ini %} +user = postfix +password = nope +hosts = 127.1 +dbname = mail +query = SELECT destination FROM aliases WHERE origin='%s'; +{% endhighlight %} + +## Conclusion +This should be enough Postfix configuration, for now. Next part involves +Dovecot, which will enable IMAP. It will also provide the SASL mechanism +defined in this part. + +[freebsd-ports]: https://www.freebsd.org/ports/ +[home]: https://www.tyil.work/ +[part-1]: https://www.tyil.work/tutorials/freebsd-mailserver-part-1-preparations/ +[postfix]: http://www.postfix.org/ +[sendmail]: http://www.sendmail.com/sm/open_source/ diff --git a/_posts/2016-10-31-freebsd-mailserver-part-3-dovecot-imap-sasl.md b/_posts/2016-10-31-freebsd-mailserver-part-3-dovecot-imap-sasl.md new file mode 100644 index 0000000..4fa4800 --- /dev/null +++ b/_posts/2016-10-31-freebsd-mailserver-part-3-dovecot-imap-sasl.md @@ -0,0 +1,227 @@ +--- +title: "FreeBSD email server - Part 3: Dovecot, IMAP and SASL" +date: 2016-10-31 07:57:50 +tags: Tutorial FreeBSD Email Installation +layout: post +authors: + - ["Patrick Spek", "https://www.tyil.work"] +--- + +# FreeBSD email server - Part 3: IMAP and SASL with Dovecot +Welcome to the second part of my FreeBSD email server series. In this series, I +will guide you through setting up your own email service. Be sure to read the +previous parts before trying to continue on this part in case you have not done +so yet. + +This part will guide you through setting up [Dovecot][dovecot]. This service +will deal with the SASL authentication to your email server and making your email +boxes accessible via IMAP. While this guide does not cover POP3 functionality, +Dovecot can handle this as well. + +Just like the Postfix setup, Dovecot has quite a few configuration options to +set before it will work as expected in this setup. If you have questions after +reading the full guide, please find me on IRC. You can find details on how to +do so on [my homepage][home]. + +## Installing Dovecot +Dovecot will also be installed from the ports tree from FreeBSD. As this guide +assumes you are working through them in order, explanation of acquiring the +ports tree will be omitted here. + +You can start the installation procedure with the following commands. + +{% highlight sh %} +cd /usr/ports/mail/dovecot2 +make configure install +{% endhighlight %} + +Again, like with the Postfix installation, leave the default options on and add +the `PGSQL` option so Dovecot can use PostgreSQL as the database back-end. + +## Enabling Dovecot +Enable the Dovecot service for rcinit. + +{% highlight sh %} +echo 'dovecot_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +## Configuring Dovecot +To start of with Dovecot configuration, copy over the sample files first. + +{% highlight sh %} +cp -r /usr/local/etc/dovecot/example-config/* /usr/local/etc/dovecot/. +{% endhighlight %} + +Now you can start editing a number of pesky files. The file names of the +headings all appear relative to `/usr/local/etc/dovecot`. + +### dovecot.conf +Here you only have to set which protocols you want to enable. Set them as +follows. + +{% highlight ini %} +protocols = imap lmtp +{% endhighlight %} + +### conf.d/10-master.cf +The `master.cf` configuration file indicates which sockets Dovecot should use +and provide and as which user its processes should be ran. Keep the defaults as +they are, with the exception of the following two blocks. + +#### service imap-login +This will enable imaps, IMAP over SSL, and disable plain IMAP. + +{% highlight ini %} +service-imap-login { + inet_listener imap { + port = 0 + } + + inet_listener imaps { + port = 993 + ssl = yes + } +} +{% endhighlight %} + +#### services +This will instruct Dovecot to provide a service for authentication and `lmtp` +the **local mail transport protocol**. This is required to deliver the email +files into the correct email box location in the file system. + +{% highlight ini %} +service auth { + unix_listener auth-userdb { + mode = 0600 + user = postfix + group = postfix + } + + unix_listener /var/spool/postfix/private/auth { + mode = 0666 + user = postfix + group = postfix + } + + user = dovecot +} + +service lmtp { + unix_listener /var/spool/postfix/private/dovecot-lmtp { + mode = 0600 + user = postfix + group = postfix + } +} + +service auth-worker { + user = postfix +} +{% endhighlight %} + +### conf.d/10-ssl.conf +Here you have to enable SSL and provide the correct paths to your SSL key in +order for Dovecot to work with them. + +{% highlight ini %} +ssl = required +ssl_cert = < /usr/local/etc/letsencrypt/live/domain.tld/fullchain.pem +ssl_key = < /usr/local/etc/letsencrypt/live/domain.tld/privkey.pem +{% endhighlight %} + +### conf.d/10-mail.conf +The mail.conf location instructs Dovecot which location to appoint for storing +the email files. `%d` expands to the domain name, while `%n` expands to the +local part of the email address. + +{% highlight ini %} +mail_home = /srv/mail/%d/%n +mail_location = maildir:~/Maildir +{% endhighlight %} + +Make sure the location set by `mail_home` exists and is owned by `postfix`! + +{% highlight sh %} +mkdir -p /srv/mail +chown postfix:postfix /srv/mail +{% endhighlight %} + +### conf.d/10-auth.conf +This file deals with the authentication provided by Dovecot. Mostly, which +mechanisms should be supported and what mechanism should be used to get the +actual credentials to check against. Make sure the following options are set +as given + +{% highlight ini %} +disable_plaintext_auth = yes +auth_mechanisms = plain +{% endhighlight %} + +Also, make sure `!include auth-system.conf.ext` is commented **out**. It is not +commented out by default, so you will have to do this manually. In addition, +you have to uncomment `!include auth-sql.conf.ext`. + +### conf.d/auth-sql.conf.ext +This is the file included from `10-auth.conf`. It instructs Dovecot to use SQL as +the driver for the password and user back-ends. + +{% highlight ini %} +passdb { + driver = sql + args = /usr/local/etc/dovecot/dovecot-sql-conf.ext +} + +userdb { + driver = prefetch +} + +userdb { + driver = sql + args = /usr/local/etc/dovecot/dovecot-sql-conf.ext +} +{% endhighlight %} + +### dovecot-sql.conf.ext +The final configuration file entails the queries which should be used to get the +required information about the users. Make sure to update the `password` and possibly +other parameters used to connect to the database. You may have to update the `125` as +well, as this has to be identical to the `UID` of `postfix`. + +As a side note, if you are following this tutorial on a machine that does +**not** support Blowfish in the default glib, which is nearly every GNU+Linux +setup, you **can not** use `BLF-CRYPT` as the `default_pass_scheme`. You will +have to settle for the `SHA-512` scheme instead. + +{% highlight ini %} +driver = pgsql +connect = host=127.1 dbname=mail user=postfix password=incredibly-secret! +default_pass_scheme = BLF-CRYPT +password_query = \ + SELECT \ + local AS user, \ + password, \ + '/srv/mail/%d/%n' AS userdb_home, \ + 125 AS userdb_uid, \ + 125 AS userdb_gid \ + FROM users \ + WHERE local='%n' AND domain='%d'; + +user_query = \ + SELECT \ + '/srv/mail/%d/%n' AS home \ + 125 AS uid, \ + 125 AS gid \ + FROM users \ + WHERE local='%n' AND domain='%d'; +{% endhighlight %} + +## Conclusion +After this part, you should be left with a functioning email server that +provides IMAP over a secure connection. While this is great on itself, for +actual use in the wild, you should setup some additional services. Therefore, +in the next part, we will deal with practices that "authenticate" your emails +as legit messages. Be sure to read up on it! + +[dovecot]: http://dovecot.org/ +[home]: https://www.tyil.work/ + diff --git a/_posts/2016-10-31-freebsd-mailserver-part-4-message-authentication.md b/_posts/2016-10-31-freebsd-mailserver-part-4-message-authentication.md new file mode 100644 index 0000000..d1c8631 --- /dev/null +++ b/_posts/2016-10-31-freebsd-mailserver-part-4-message-authentication.md @@ -0,0 +1,159 @@ +--- +title: "FreeBSD email server - Part 4: Message authentication" +date: 2016-10-31 20:00:38 +tags: Tutorial FreeBSD Email Installation +layout: post +authors: + - ["Patrick Spek", "https://www.tyil.work"] +--- + +# FreeBSD email server - Part 4: Message authentication +Welcome to another part in the FreeBSD email server series. This time, we are +going to setup some mechanisms to deal with message authentication. This +practice will make other email providers accept your email messages and deliver +them properly in the inbox of the receiving user, instead of their spam box. + +We will do so using three of the most common practices: [SPF][spf], +[DKIM][dkim] and [DMARC][dmarc]. + +## DKIM +### Installation +The tools for DKIM are easily installed using `pkg`. + +{% highlight sh %} +pkg install opendkim +{% endhighlight %} + +### Configuration +Write the following configuration into `/usr/local/etc/mail/opendkim.conf`. + +{% highlight conf %} +# logging +Syslog yes + +# permissions +UserID postfix +UMask 007 + +# general settings +AutoRestart yes +Background yes +Canonicalization relaxed/relaxed +DNSTimeout 5 +Mode sv +SignatureAlgorithm rsa-sha256 +SubDomains no +X-Header yes +OversignHeaders From + +# tables +KeyTable /usr/local/etc/opendkim/key.table +SigningTable /usr/local/etc/opendkim/signing.table + +# socket +Socket inet:8891@localhost + +# domains +Domain domain.tld.privkey +KeyFile /usr/local/etc/opendkim/domain.tld +Selector mail +{% endhighlight %} + +#### Postfix +Postfix needs to be instructed to sign the messages with a DKIM header using +the opendkim service. You can do so by inserting the following configuration +block somewhere around the end of `/usr/local/etc/postfix/main.cf`. + +{% highlight ini %} +# milters +milter_protocol = 2 +milter_default_action = reject +smtpd_milters = + inet:localhost:8891 + non_smtpd_milters = + inet:localhost:8891 +{% endhighlight %} + +#### System service +OpenDKIM runs as a system service. As such, you will have to enable this +service in rcinit. This is a simple step, achieved with the given command. + +{% highlight sh %} +echo 'milteropendkim_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +Do not forget to actually start the service when you are done with the +tutorial! + +### Creating and using keys +In order to use DKIM, you will need to generate some keys to sign the messages +with. You cannot use your Let's Encrypt SSL keys for this. First, create a +directory to house your domain's keys. + +{% highlight sh %} +mkdir -p /usr/local/etc/opendkim/keys/domain.tld +chown -R postfix:wheel $_ +{% endhighlight %} + +Next up, generate your first key. + +{% highlight sh %} +opendkim-genkey -D /usr/local/etc/opendkim/keys -b 4096 -r -s $(date +%Y%m%d) -d domain.tld +{% endhighlight %} + +I tend to use the current date for the key names so I can easily sort them by +the most recent one. + +Afterwards, you will have to add a line to two separate files to instruct DKIM +to use this key for a certain domain when signing mail. These are fairly +straightforward and can be done using a simple `echo` as well. + +{% highlight sh %} +echo '*@domain.tld domain.tld' >> /usr/local/etc/opendkim/signing.table +echo "domain.tld domain.tld:$(date +%Y%m%d):/usr/local/etc/opendkim/keys/domain.tld/$(date +%Y%m%d).private" >> /usr/local/etc/opendkim/key.table +{% endhighlight %} + +### Adding the DNS records +You may have already noticed that `opendkim-genkey` also creates a `.txt` file +in addition to the private key. This text file contains the DNS record value +you need to add for your domain's DNS. Add the record to your DNS server, and +simply wait for it to propagate. + +## SPF +SPF is simply a DNS record that shows which IPs are allowed to email for that +domain. + +### Adding the DNS records +A simple example for an SPF record is the following. It allows mail to be sent +in the domain's name from any IP listed in the MX records. + +{% highlight plain %} +v=spf1 mx -all +{% endhighlight %} + +## DMARC +DMARC is, like SPF, a DNS record. It tells how to deal with messages coming +from the server and where to report abuse of your server. Some of the larger +email providers send out reports to the address given in the DMARC record so +you can figure out whether someone is spamming from your servers, for example. + +### Adding the DNS records +A simple DMARC policy to get started with is to quarantine all emails that fail +authentication. This means the emails will go into the receiving user's spam +box. In addition, abuse reports will be sent to the address defined in the +`rua`. + +{% highlight plain %} +v=DMARC1; p=quarantine; rua=mailto:abuse@domain.tld +{% endhighlight %} + +## Conclusion +These few simple measures will make receiving servers trust the authenticity of +the mails you send. In effect, your messages will be much less likely to be +marked as spam. However, you are a target of spam as well. How you can deal +with that, will be available in the next part of this series. + +[dkim]: http://www.dkim.org/ +[dmarc]: http://dmarc.org/ +[spf]: https://en.wikipedia.org/wiki/Sender_Policy_Framework + diff --git a/_posts/2016-10-31-freebsd-mailserver-part-5-filtering-mail.md b/_posts/2016-10-31-freebsd-mailserver-part-5-filtering-mail.md new file mode 100644 index 0000000..909449e --- /dev/null +++ b/_posts/2016-10-31-freebsd-mailserver-part-5-filtering-mail.md @@ -0,0 +1,132 @@ +--- +title: "FreeBSD email server - Part 5: Filtering mail" +date: 2016-10-31 20:02:19 +tags: Tutorial FreeBSD Email Installation +layout: post +authors: + - ["Patrick Spek", "https://www.tyil.work"] +--- + +# FreeBSD email server - Part 5: Filtering mail +Being able to send mail and not be flagged as spam is pretty awesome on itself. +But you also get hit by a lot of spam. The more you give out your email address +and domain name, the more spam you will receive over time. I welcome you to +another part of the FreeBSD email server series. In this part, we will set up +email filtering at the server side. + +We will accomplish this with a couple packages, [SpamAssassin][spamassassin] +and [Pigeonhole][pigeonhole]. The former deals with scanning the emails to +deduce whether it is spam or not. The latter filters messages. We will use this +filtering to drop emails marked as spam by SpamAssassin into the Junk folder, +instead of the inbox. + +## Installing the packages +Both packages are available through FreeBSD's `pkg` utility. Install them as +such. + +{% highlight sh %} +pkg install dovecot-pigeonhole spamassassin +{% endhighlight %} + +## SpamAssassin +### Enabling the service +Like most services, you have to enable them as well. Pigeonhole is an extension +to Dovecot, and Dovecot will handle this one. SpamAssassin requires you to +configure the service as well. You can enable it and set sane configuration to +it with the following two commands. + +{% highlight sh %} +echo 'spamd_enable="YES"' >> /etc/rc.conf.local +echo 'spamd_flags="-u spamd -H /srv/mail"' >> /etc/rc.conf.local +{% endhighlight %} + +### Acquiring default spam rules +SpamAssassin has to "learn" what counts as *spam* and what counts as *ham*. To +fetch these rules, you should execute the updates for SpamAssassin with the +following command. + +{% highlight sh %} +sa-update +{% endhighlight %} + +You most likely want to run this once every while, so it is advised to setup a +[cronjob][cronjob] for this purpose. + +## Postfix +In order to have mails checked by SpamAssassin, Postfix must be instructed to +pass all email through to SpamAssassin, which will hand them back with a +`X-Spam-Flag` header attached to them. This header can be used by other +applications to treat it as spam. + +### master.cf +There's not much to include to the already existing Postfix configuration to +enable SpamAssassin to do its job. Just open `/usr/local/etc/postfix/master.cf` +and append the block given below. + +{% highlight ini %} +spamassassin unix - n n - - pipe + user=spamd argv=/usr/local/bin/spamc + -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient} +{% endhighlight %} + +## Pigeonhole +Pigeonhole is an implementation of Sieve for Dovecot. It deals with filtering +messages on the server side using a set of rules, defined in a file usually +named `sieve`. This file is generally saved at +`/srv/mail/domain.tld/user/sieve`. A default file to filter spam out is the +following example. + +{% highlight sieve %} +require [ + "fileinto", + "mailbox" +]; + +if header :contains "X-Spam-Flag" "YES" { + fileinto :create "Junk"; + stop; +} +{% endhighlight %} + +This looks for the `X-Spam-Flag` header, which is added by SpamAssassin. If it +is set to `YES`, this indicates SpamAssassin thinks the message is spam. As +such, sieve is instructed to filter this message into the folder `Junk`, and to +create this folder if it does not exist yet. The `stop;` makes sieve stop +trying to process this message further based on later rules. + +## Dovecot +Dovecot needs some additional configuration to work with Pigeonhole. Modify the +following files and add the contents described. + +### conf.d/20-lmtp.conf +This will enable Pigeonhole in Dovecot. + +{% highlight ini %} +protocol lmtp { + mail_plugins = $mail_plugins sieve +} +{% endhighlight %} + +### conf.d/90-plugin.conf +This configures Pigeonhole to look for a file named `sieve` in the mailbox +homedir, and execute that when delivering mail. + +{% highlight ini %} +plugin { + sieve = /srv/mail/%d/%n/sieve +} +{% endhighlight %} + +## Conclusion +Spam is a pain, especially if you get a lot of it. The configuration added in +this part of the FreeBSD email server series should get rid of most of it. This +also concludes the series. If you have any questions or suggestions, please +contact me via any of the methods detailed on [my home page][home]. + +Thanks for reading along, and enjoy your very own email server! + +[cronjob]: # +[home]: https://www.tyil.work/ +[pigeonhole]: http://pigeonhole.dovecot.org/ +[spamassassin]: https://spamassassin.apache.org/ + diff --git a/_posts/2016-11-24-freebsd-mailserver-calendars-and-contacts.md b/_posts/2016-11-24-freebsd-mailserver-calendars-and-contacts.md new file mode 100644 index 0000000..b29a123 --- /dev/null +++ b/_posts/2016-11-24-freebsd-mailserver-calendars-and-contacts.md @@ -0,0 +1,140 @@ +--- +title: "FreeBSD email server - Part +: Calendars and contacts" +date: 2016-11-24 08:26:09 +tags: Tutorial FreeBSD Email CalDAV CardDAV Installation +layout: post +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# FreeBSD email server - Part +: Calendars and contacts +This guide is an addition to the [FreeBSD email server series][tutorial-email]. +It is not required for your email server to operate properly, but it is often +considered a very important feature for those who want to switch from a third +party email provider to their own solution. It does build upon the completed +series, so be sure to work through that before starting on this. + +## Install required packages +{% highlight sh %} +pkg install py27-radicale +{% endhighlight %} + +## Configure Radicale +### /usr/local/etc/radicale/config +Open up the `/usr/local/etc/radicale/config` file, and update each `[block]`. + +#### [server] +The server is binding to `localhost` only. This way it is not accessible on +`:5232` from outside the server. Outside access will be provided through an +nginx reverse proxy instead. + +{% highlight ini %} +hosts = 127.1:5232 +daemon = True + +dns_lookup = True + +base_prefix = / +can_skip_base_prefix = False + +realm = Radicale - Password required +{% endhighlight %} + +#### [encoding] +{% highlight ini %} +request = utf-8 +stock = utf-8 +{% endhighlight %} + +#### [auth] +{% highlight ini %} +type = IMAP + +imap_hostname = localhost +imap_port = 143 +imap_ssl = False +{% endhighlight %} + +#### [storage] +{% highlight ini %} +type = filesystem +filesystem_folder = /usr/local/share/radicale +{% endhighlight %} + +#### [logging] +{% highlight ini %} +config = /usr/local/etc/radicale/logging +{% endhighlight %} + +### /usr/local/etc/radicale/logging +This file is fine on the defaults in FreeBSD 11. This saves you from +configuring a little bit. + +## Configure Dovecot +### Enable imap +This option was disabled in the [IMAP server tutorial][tutorial-email], +however, if we want to auth using the same credentials as the mailserver, this +option is needed again. Bind it to `localhost`, so it can only be used +internally. In `/usr/local/etc/dovecont/conf.d/10-master.conf`, enable the +`imap` port again: + +{% highlight conf %} +... +service imap-login { + inet_listener imap { + address = 127.1 + port = 143 + } + ... +} +... +{% endhighlight %} + +## Configure nginx +To make using the service easier, you can setup [nginx][nginx] to act as a +reverse proxy. If you followed the [webserver tutorial][tutorial-webserver], +you already have the basics for this set up. I do recommend you check this out, +as I will only explain how to configure a virtual host to deal with the reverse +proxy here. + +### Setup a reverse proxy +Assuming you have taken the crash-course in setting up the nginx webserver, you +can attain a reverse proxy using the following config block. Note that this block +only does HTTPS, as I use HTTP only to redirect to HTTPS. + +{% highlight nginx %} +# static HTTPS +server { + # listeners + listen 443 ssl; + server_name radicale.domain.tld; + + # enable HSTS + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; + + # keys + ssl_certificate /usr/local/etc/letsencrypt/live/domain.tld/fullchain.pem; + ssl_certificate_key /usr/local/etc/letsencrypt/live/domain.tld/privkey.pem; + + # / handler + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.1:5232; + } +} +{% endhighlight %} + +## Enable the service at startup +{% highlight sh %} +echo 'radicale_enable="YES"' >> /etc/rc.conf.local +{% endhighlight %} + +## Start the server +{% highlight sh %} +service radicale start +{% endhighlight %} + +[nginx]: https://www.nginx.com/ +[tutorial-email]: https://www.tyil.work/tutorials/freebsd-mailserver-part-1-preparations/ +[tutorial-webserver]: https://www.tyil.work/tutorials/setup-nginx-with-lets-encrypt-ssl/ diff --git a/_posts/2017-09-14-how-to-git.md b/_posts/2017-09-14-how-to-git.md new file mode 100644 index 0000000..7c4f21f --- /dev/null +++ b/_posts/2017-09-14-how-to-git.md @@ -0,0 +1,185 @@ +--- +title: "How to: git" +date: 2017-09-14 19:46:34 +tags: Tutorial Git +layout: post +authors: + - ["Patrick Spek", "http://tyil.work"] +--- + +# How to: git +This guide will explain how to use `git` more efficiently, and why you should +use it as such. + +## Forking +When working in a team, there's generally a remote server which is used to sync +your repositories. There are gratis services, such as [GitHub][github], +[Gitlab][gitlab], [GOGS][gogs], and others. These services also allow you to +*fork* a repository. This basically makes a copy of the entire repository for +your own use. In it, you have full control over the branches, tags, merge +process and everything else you want to do with it. + +One the main reasons to do this is so you do not have to clutter up the main +repository with a ton of branches (these are explained later in the post). If +there are two people working in the same branch, it can help reduce conflicts, +as each developer is working on the branch in his own fork. + +As such, **always** use a fork. If the service does not have a fancy button for +you to click, you can still fork manually. Simply clone their repository as +usual, set a new remote and push it there: + +{% highlight sh %} +git clone git@domain.tld:them/repo.git +cd repo +git remote rename origin upstream +git remote add origin git@domain.tld:you/repo.git +git push origin master +{% endhighlight %} + +The default naming convention uses `upstream` for the base of your fork, and +`origin` for your remote version of the repository. If a merge request is +accepted on the original repo, you can apply it to your fork using + +{% highlight sh %} +git pull upstream master +{% endhighlight %} + +## Branching +Branching is the art of using separate branches to introduce new code into your +`master` branch. Every git repository starts with a `master` branch by default. +This is the *main* branch of your repository. + +Every time you want to add new code to your project, make a branch for the +feature or issue you are trying to solve. This way, you can commit freely +without having to worry about having untested or possibly broken code in the +`master` branch. If something were to come up with a higher priority, such as a +critical bug, you can simply create a new branch off of `master`, fix it and +merge that back into `master`, without having to worry about that other feature +you were working on, which is not in a releasable state yet. Once the fix is +applied, you go back to your feature branch on continue working on the cool new +stuff you wanted to implement. Now, the bug is fixed, and no code has been +released that should not have been released. If that's not convincing enough, +try some of the [Stack Overflow posts][so-git-branch] on this very topic. + +Branches can be made at your leisure, with next to no overhead on your project. +Do not be scared to play around with your code in a new branch to test +something out. You can also delete branches as quickly as you made them if you +are not satisfied with the result. + +Creating branches is done using `git checkout -b new-branch`. If you need to +switch to another existing branch to change something, use +`git checkout other-branch`. Deleting a branch can be done using +`git branch -D old-branch`. You can get a list of all branches in the +repository with `git branch`. The current branch is marked with an \*. + +If you start a new branch to implement a feature, be sure to always branch off +of `master`, unless you have a very compelling reason not to do so. If you are +not sure what reasons would validate branching off of another branch, you +should just branch off of `master`. If you branch off of another branch, you +will have the commit history of the other branch. This often includes commits +not accepted into master yet, which might result into commits getting into +master which should not be there (yet), or annoying merge conflicts later on. + +### Merging +Using multiple branches brings along the concept of *merging* branches +together. When working in a group, this is generally done by maintainers of the +upstream repository, via a *merge request*. For some reason, certain services +have named this as a *pull request* instead. The base idea of the process is as +follows: + +- Pull the latest `upstream/master` +- Create a new branch +- Apply the change you want +- Issue a merge request via the service you are using + - Generally, you want your change to be merged into their `master` branch +- Add a title and a description of your change: What does it do, and why should it be accepted +- Optionally, discuss the changes with the upstream maintainers +- Optionally, make a couple of changes to your branch, and push it again +- Upstream maintainer accepts your change + +When everything worked out, the upstream repository now contains your changes. +If you pull their branch again, it will contain your code. Using the merge +request process, your code can be easily reviewed by others, and discussed if +needed. + +## Committing +Whenever you have changed anything in the repository and you wish to share +these changes, you have to commit the changes. Committing in general is not +something people tend to have issues with. Simple add the changes you want to +commit using `git add` (add the `-p` switch if you want to commit only parts of +a changed file), then `git commit` and enter a descriptive message. And that is +where most annoyances come from: the commit *message*. There are no hard rules +on this forced by git itself. There are, however, some de-facto standards and +best practices which you should always follow. Even if you never intend to +share the repository with other people, having good commit messages can help +you identify a certain change when you look back into the history. + +A git commit message should be short, no more than 79 characters, on the first +line. It should be readable as "this commit message will ...", where your +commit message will replace the "...". It is a de-facto standard to start your +commit message with a capital letter, and leave off a finishing period. You do +not *have* to adhere to if you hate this, but be sure that all your commits are +consistent in how they are formatted. + +If you need to explain anything beyond that, such as a rationale for the +change, or things the reviewer should pay attention to in this particular +commit, you can leave an empty line and publish this message in the commit +body. + +When you are using a bug tracking system, you might also want to have a footer +with additional information. On services such as [Gitlab][gitlab] and +[GitHub][github], you can close issues by adding "Closes: #1" in the commit +message footer. A full commit message with all these things might look as +follows: + +``` +Fix overflow issue in table rendering mechanism + +An overflow issue was found in the table rendering mechanism, as explained in +CVE-0123-45678. Regression tests have been included as well. + +Closes: #35 +``` + +In order to achieve these kind of messages, you need to be sure that your +commits can fit in to this structure. This means you need to make small +commits. Having many smaller commits makes it easier to review the changes, +keep short, descriptive messages to describe each change, and revert a single +change in case it breaks something. + +### Signing your commits +You can set up git to cryptographically sign each commit you make. This will +ensure that the commit you made is proven to be from you, and not someone +impersonating you. People impersonating you might try to get harmful code into +a repo where you are a trusted contributor. Having all commits signed in a +repository can contribute in verifying the integrity of the project. + +Recently, [Github][github] has added the **Verified** tag to commits if the +commit contains a correct signature. + +To enable signing of all commits, add the following configuration to your +`~/.gitconfig`: + +{% highlight ini %} +[commit] + gpgsign = true + +[user] + signingkey = 9ACFE193FFBC1F50 +{% endhighlight %} + +Ofcourse, you will have to update the value of the `signingkey` to match +the key you want to sign your commits with. + +## Closing words +I hope this post will help you in your adventures with git. It is a great tool +or working on projects together, but it gets much better when you stick to some +best practices. If you have any suggestions for this post, or any questions +after finishing it, contact me via any method listed on [my home page][home]. + +[github]: https://github.com +[gitlab]: https://gitlab.com +[gogs]: https://gogs.io +[home]: https://tyil.work +[so-git-branch]: https://softwareengineering.stackexchange.com/questions/335654/git-what-issues-arise-from-working-directly-on-master + diff --git a/_posts/2017-09-28-perl6-creating-a-background-service.adoc b/_posts/2017-09-28-perl6-creating-a-background-service.adoc new file mode 100644 index 0000000..c642964 --- /dev/null +++ b/_posts/2017-09-28-perl6-creating-a-background-service.adoc @@ -0,0 +1,159 @@ +--- +date: 2017-09-28 15:11:43 +tags: Tutorial Perl6 Programming +description: > + I've recently made some progress on Shinrin, a centralized logging system in + Perl 6. This has to run as service, which means that for most service + managers it has to be able to run in the background. +--- += Perl 6 - Creating a background service +:toc: preamble + +I've recently made some progress on +https://github.com/scriptkitties/perl6-Shinrin[Shinrin], a centralized logging +system in Perl 6. This has to run as service, which means that for most service +managers it has to be able to run in the background. + +[NOTE] +==== +If you just want to get to the solution and don't care for the details, just +head straight to link:#the-final-solution[the full script]. +==== + +== It's not possible! +After a lot of trying and talking with the folks at +irc://chat.freenode.net:6697/#perl6[#perl6] I was told that it is not possible +to do this in pure Perl 6, explained by people with more knowledge than I have +on the internals: + +[quote, jnthn] +____ +(jnthn suspects fork + multi-threaded VM = pain) Since fork only clones one +thread - the one that called it. So suddenly you've got an instance of the VM +missing most of its threads. +____ + +[quote, geekosaur] +____ +The most common failure mode is that some thread is holding e.g. a mutex (or a +userspace lock) during the fork. The thread goes away but the lock is process +level and remains, with nothing around to know to unlock it. So then things +work until something else needs that lock and suddenly you deadlock. +____ + +Not much later, `jnthn` https://github.com/perl6/doc/commit/8f9443c3ac[pushed a +commit] to update the docs to clarify that a `fork` call through `NativeCall` +will probably not give the result you were hoping for. + +== Or is it? +Luckily, the same people were able to think up of a work-around, which can be +made in POSIX sh, so it's usable on any decent OS. The workaround is to let a +little shell script fork into the background, and let that run the Perl +application. + +=== A first example +This is fairly simple to create, as in this example to launch `shinrind` in the +background: + +[source,sh] +---- +#! /usr/bin/env sh + +main() +{ + perl6 -Ilib bin/shinrind "$@" +} + +main "$@" & +---- + +This works just fine if the working directory is correct. This means you need +to be in the parent directory to `lib` and `bin` of the program to make it +work. + +== Improving the forking script +While that short script works fine to show a proof of concept, in order to make +it viable for real-world scenarios, it can use some improvements. After all, it +would be annoying if you'd have to `cd` to a specific directory any time you +want to start your application. + +=== Ensure you are in the directory you should be in +So for starters, let's make sure that you can run it from anywhere on your +system. For this, you should set the working directory for the script, so you +don't have to do it manually. Because the script runs in its own subshell, the +shell you're working from remains unaffected. + +A POSIX compliant way to get the directory the script is stored in is as +follows: + +[source,sh] +---- +DIR=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) +---- + +This will set `$DIR` to the path of the directory the shell script is stored +in. You can simply `cd` to that and be assured you're in the right directory. + +In Perl 6, it is expected for executable files to live in the `bin` directory +of your project repository. So you should actually be in the parent of the +directory holding your script. Furthermore, you should check the `cd` command +executed correctly, just to be safe. + +[source,sh] +---- +cd -- "${DIR}/.." || exit +---- + +=== Disable `STDOUT` and `STDERR` +A started service should not be polluting your interactive shell, so you should +disable (or otherwise redirect) `STDOUT` and `STDERR`. This is done in the +shell using a small bit of code behind whatever you want to redirect: + +[source,sh] +---- +> /dev/null 2>&1 +---- + +This will set `STDOUT` to `/dev/null`, and set `STDERR` to the same stream as +`STDOUT`, which in effect will make all output go to `/dev/null`. If you want +to log everything to a single file, you can replace `/dev/null` with another +file of your choice. If you don't want logs to be overwritten on each start, +use a `>>` instead of a single `>` at the start. + +If you want to log errors and output in different files, you can use the +following: + +[source,sh] +---- +> /var/log/service.log 2> /var/log/service.err +---- + +This will put standard output in `/var/log/service.log` and errors in +`/var/log/service.err`. + +=== Fork just the Perl 6 program +In the initial example, I put the `&` behind the `main` call, at the bottom of +the script. While this works just fine for most simple usage, if you want to do +additional chores, like creating a pidfile after starting the Perl 6 program, +you're out of luck. If you were to only fork the Perl 6 application, you could +handle some other cases in the shell script. + +== The final solution +For those eager to just get going with this, here is the complete example +script to just fork your Perl program into the background: + +[source,sh] +---- +#! /usr/bin/env sh + +readonly DIR=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) + +main() +{ + cd -- "${DIR}/.." || exit + + perl6 -Ilib bin/shinrind "$@" > /dev/null >2&1 & +} + +main "$@" +---- diff --git a/_posts/2017-11-01-hacktoberfest-2017.adoc b/_posts/2017-11-01-hacktoberfest-2017.adoc new file mode 100644 index 0000000..ada4edd --- /dev/null +++ b/_posts/2017-11-01-hacktoberfest-2017.adoc @@ -0,0 +1,197 @@ +--- +date: 2017-11-01 12:37:53 +tags: Article FreeSoftware Github Hacktoberfest Contributions +description: > + This year I actively participated in the Hacktoberfest event, which is 'a + month-long celebration of open source software'. Ironic, given that the + companies organising it don't have their own software stack open source. + Nevertheless, I did contribute to free software, and this article lists these + contributions. +--- += Hacktoberfest 2017 +:toc: preamble + +This year I actively participated in the Hacktoberfest event, which is "a +month-long celebration of open source software". Ironic, given that the +companies organising it don't have their own software stack open source. + +I've found some issues to solve in https://perl6.org/[Perl 6] projects, and +that lead to trying to solve issues in some other projects, and eventually I +got more PRs out than there are days in the month. It did go at the cost of +some sleep, but in the end it seems worth it. In this article, I'll give a +small overview of all those PRs, in no particular order. + +== Projects contributed to +=== Funtoo +==== funtoo/boot-update +- https://github.com/funtoo/boot-update/pull/14 + +When reinstalling my server to try out https://docker.com[Docker], I noticed an +error in the output of the `boot-update` utility, a tool from +https://www.funtoo.org/Welcome[Funtoo] to make installing and configuring the +bootloader easier. The error itself was a small type of a `-` which had to be a +`_`. + +==== scriptkitties/overlay +- https://github.com/scriptkitties/overlay/pull/14 +- https://github.com/scriptkitties/overlay/pull/15 +- https://github.com/scriptkitties/overlay/pull/16 + +This is the overlay of the https://scriptkitties.church[Scriptkitties] +community. It's got some additional software released under a free license that +is not available in the main portage repository. Most of the packages in here +are of software made by the Scriptkitties community. + +This month I updated the readme to be in asciidoc, my new favourite format for +documentation. The Travis builds should also no longer throw errors, so those +can be used again to ensure the overlay is meeting quality standards. One +package has also been updated to be at it's latest version again. + +=== Perl 6 +==== moznion/p6-HTML-Escape +- https://github.com/moznion/p6-HTML-Escape/pull/1 + +On this repository, I added a subroutine to also handle unescaping HTML special +characters. Sadly, the owner of this repository has shown no sign of life, and +the PR remains open. + +==== rakudo/rakudo +- https://github.com/rakudo/rakudo/pull/1180 + +This is a rather small issue, but I noticed it when compiling Perl 6 with +https://github.com/tadzik/rakudobrew[Rakudobrew] and it annoyed me. +http://zoffix.com/[Zoffix] was a great help in getting me started on this one, +and in general with many other Perl related contributions as well. + +==== scriptkitties/perl6-IRC-Client-Plugin-Github +- https://github.com/scriptkitties/perl6-IRC-Client-Plugin-Github/pull/2 + +A neat feature for the Github notification system, HMAC adds a header that can +be used to verify the body of the request, and can be used to verify the other +end of the connection knows the right "secret". Inspired by a Perl 6 bot that +already did this, I made a PR to make this a proper +https://github.com/zoffixznet/perl6-IRC-Client[IRC::Client] plugin. It is still +being tested in https://github.com/scriptkitties/musashi[musashi]. + +==== perl6/roast +- https://github.com/perl6/roast/pull/342 + +Roast is the test suite for Perl 6. There was an open issue for the IO::File +tests, which needed expansion. As my first contribution during a Perl 6 +squashaton, I expanded these tests to fix the issue that was open for it. + +==== vim-perl/vim-perl6 +- https://github.com/vim-perl/vim-perl6/pull/9 +- https://github.com/vim-perl/vim-perl6/pull/10 + +This first PR has become a bit of a drag, with the maintainers not responding +for two weeks, but suddenly very eager to respond when I mention I'm going to +fork off and update the reference on the Perl documentation to my fork. +Nonetheless, it's sorted out, and the abbreviations for unicode operators +have been merged in! + +==== timo/json_fast +- https://github.com/timo/json_fast/pull/32 + +`JSON::Fast` is the de-facto standard for dealing with JSON data in Perl 6 it +seems. For my work with `App::Cpan6` I wanted the JSON data to be ordered, so I +added that as an option when calling `to-json`. Having the JSON data ordered +makes it easier to compare diffs of two different versions of the data, making +git diffs a lot cleaner. + +Sadly, timo has not merged the PR yet, so I can't properly depend on it in +`App::Cpan6`. + +==== scriptkitties/perl6-SemVer +- https://github.com/scriptkitties/perl6-SemVer/pull/1 + +This is one of the new projects I started. It is intended to be used in +`App::Cpan6`, since that uses https://semver.org[Semantic Versioning] for all +modules it works with. This module defines a class that can interpret a SemVer +notation, and exposes methods to bump any part of the version. + +==== perl6/doc +- https://github.com/perl6/doc/pull/1614 + +This has been one of the more annoying PRs to work on, as the current `zef` +maintainer insists everything but his module is wrong, and seemed very +uninterested to improve the situation for users. After some discussion on IRC, +some more discussion on IRC, and then some discussion on the PR itself, I +decided to just word the paragraph differently. + +I am still interested in improving the documentation here and the ecosystem +itself, mainly the `META6.json` specification, and getting `zef` to play nice +with this spec. If anyone else is interested in helping me out on this, do +message me on IRC! + +==== perl6/perl6.org +- https://github.com/perl6/perl6.org/pull/86 +- https://github.com/perl6/perl6.org/pull/87 + +There were some open issues for the https://perl6.org[perl6.org] website, and I +decided to take a look at some and try to fix them. This resulted in NeoVim +being added to the list of recommended editors for Perl 6, and the list of IRC +bots being updated to include all bots in use right now. + +==== scriptkitties/p6-MPD-Client +- https://github.com/scriptkitties/p6-MPD-Client/pull/1 +- https://github.com/scriptkitties/p6-MPD-Client/pull/2 + +As I was making `App::MPD::AutoQueue` and `App::MPD::Notify`, I found some +issues in `MPD::Client`. I fixed those to get my two new projects working +nicely. + +==== melezhik/sparrowdo +- https://github.com/melezhik/sparrowdo/pull/15 +- https://github.com/melezhik/sparrowdo/pull/18 + +Sparrowdo is a configuration management system, written in Perl 6. I learned +about it after a reference from the Perl 6 Weekly, and set out to try it. I ran +into some issues, which I reported and eventually fixed. + +In addition, I also rewrote the testing script for Travis, which enables +paralel builds of the tests. This has nearly halved the time required for +running the full test suite. + +==== perl6/ecosystem +- https://github.com/perl6/ecosystem/pull/371 +- https://github.com/perl6/ecosystem/pull/372 +- https://github.com/perl6/ecosystem/pull/374 + +These PRs added a module, and removed that one and more later on, since I got a +PAUSE ID and uploaded my modules to CPAN. + +==== scriptkitties/perl6-App-Cpan6 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/1 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/2 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/3 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/4 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/12 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/13 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/14 +- https://github.com/scriptkitties/perl6-App-Cpan6/pull/15 + +`App::Cpan6` is a tool I've started working on to assist me in creating new +Perl 6 modules. There's been a couple of tasks that I do often in the process +of creating a module, and those tasks should become easier and faster using +this module. + +If everything works out and I learn enough of the module installation process, +I might consider letting this deal with the installation and updating of +modules as well. + +== In retrospect +The Hacktoberfest has been an interesting month for me. I've gotten to +contribute to a project I have come to love a lot, Perl 6. I've also made some +new friends with similar goals. Sadly I can't put in this much time every month +of the year, but I would if I could! + +I learned many interesting things for Perl 6, new operators, new functions, all +kinds of cool stuff to improve my Perl scripts with. I also got to learn about +parallelizing Travis builds with the Sparrowdo project, of which I will write +another tutorial post later. + +I've greatly enjoyed contributing to all the various projects, and would +recommend other people to check it out too. The people on the respective +project's IRC channels have been a great help to me to get started, and I can +help out getting you started as well now. diff --git a/_posts/2017-11-16-perl6-setting-up-a-raspberry-perl.adoc b/_posts/2017-11-16-perl6-setting-up-a-raspberry-perl.adoc new file mode 100644 index 0000000..e58efc1 --- /dev/null +++ b/_posts/2017-11-16-perl6-setting-up-a-raspberry-perl.adoc @@ -0,0 +1,236 @@ +--- +date: 2017-11-16 11:58:40 +tags: Tutorial Perl6 RaspberryPi Installation +description: > + In this tutorial I'll get you through setting up a Raspberry Pi with Perl 6. + I am using a Raspberry Pi 3 myself, but other versions should work fine too. + However, older versions are slower, so it might take a bit longer to install + completely. +--- += Perl 6 - Setting up a Raspberry Perl +:toc: preamble + +In this tutorial I'll get you through setting up a Raspberry Pi with +https://perl6.org/[Perl 6]. I am using a Raspberry Pi 3 myself, but other +versions should work fine too. However, older versions are slower, so it might +take a bit longer to install completely. + +[NOTE] +==== +For those who have never had a Raspberry Pi before, you will need +the following: + +- Raspberry Pi board +- Power supply (5v 2A, micro USB) +- SD card of at least 4gb, but I would advise at least 8gb +- Monitor with HDMI cable +- Keyboard +==== + +Perl 6 will be installed using +https://github.com/tadzik/rakudobrew[Rakudobrew], which I'll also be using to +get https://github.com/ugexe/zef[zef] installed. Zef is the recommended module +manager for Perl 6. + +== Setting up Raspbian + +The first step is getting the OS set up. To keep this tutorial simple, I will +stick to https://www.raspbian.org/[Raspbian], but if you feel confident in your +skills you can use any other distribution or OS. Perl 6 installs the same on +all UNIX(-like) operating systems. + +=== Get the image + +First, https://www.Raspberrypi.org/downloads/raspbian/[download the Raspbian +image from the Raspberry Pi download page]. I chose the `LITE` version, but if +you prefer having a graphical desktop you can go for the `DESKTOP` version +instead. + +At the time of writing, this means I got the +`2017-09-07-raspbian-stretch-lite.zip`. If you want to verify you got the +correct download and nothing went wrong saving it to your disk, you can verify +the checksum. The checksum for your download is noted below the download links. +To get the checksum of the file you downloaded, use `sha256sum` as follows: + +NOTE: Lines prepended with a `$` are to be ran as your normal user, whereas +lines with a `#` are ment to be ran as "super user". This can be done by using +a privilege escalation program, such as +https://www.linux.com/blog/how-use-sudo-and-su-commands-linux-introduction[`sudo`]. + +[source] +---- +$ sha256sum 2017-09-07-raspbian-stretch-lite.zip +---- + +If the checksum matches the one noted below the download button you used, it +should be fine, and you can continue with extracting the image from the zip +using `unzip`: + +[source] +---- +$ unzip 2017-09-07-raspbian-stretch-lite.zip +---- + +This will result in a similarly named file, but with a `.img` extension instead +of `.zip`. This is the image that you can write to the SD card. + +=== Write the image to the SD card + +This step is pretty easy, but typos here can be disastrous for the system +you're using to write to the SD card. + +Open a terminal and run `dmesg -w` as super user (usually doable using `sudo +dmesg -w`). This will give immediate feedback when you insert your SD card, and +shows which device it is being assigned to. In my case, this was `sdb`, which +means the device file resides at `/dev/sdb`. + +Now, to actually write the image, I'll use `dd` since this is everyone's +favourite tool, it seems. If you feel adventurous enough to try out something +different, feel free to read up on +https://www.vidarholen.net/contents/blog/?p=479[Useless Use of dd]. + +Make sure to make the `if` argument point to the correct path with your +extracted raspbian image, and `of` to point to the correct device as identified +earlier. In order to be allowed to run this command, you must be root, which +can be achieved by using `sudo` or `doas` again. + +[source] +---- +# dd bs=4M status=progress if=/path/to/2017-09-07-raspbian-stretch-lite.img of=/dev/sdb +$ sync +---- + +Afterwards, plug it into your Raspberry Pi and attach all cables you might +need. Think of stuff like a keyboard, mouse, monitor, internet, power. Do power +last, as the Raspberry Pi will start immediatly once it receives power. + +=== First boot + +The Raspberry Pi should start booting the moment you supply it with power. If +you attach the HDMI after the power, it's possible you won't have display +working, so make sure HDMI is attached before powering up. + +You'll see some text scrolling by, up to a point where it asks you for a +`login`, and accepts keyboard input. The default username is `pi`, and the +default password is `Raspberry`. You are strongly advised to change the +password upon login, which can be done in the next step. + +=== Configuration + +The Raspberry Pi comes with its own configuration tool, `raspi-config`. Run +this with `sudo` prepended in front of it so you gain the right privileges. I +would advise you to at least change the user password from here. After this you +should go to `Advanced Options` and expand the filesystem. This will grow the +filesystem to the entire SD card's size. + +TIP: To get to the buttons on the bottom (`Select`, `Finish` and `Back`), use +the arrow keys to go left or right. + +You can look around the tool for other interesting things to modify. Once you +are satisfied, go back to the main menu and choose `Finish`. It will ask to +reboot, which you should accept. This will apply all the new configurations you +just made. + +=== Updating and installing additional packages + +It's rare for the system to be completely up to date after installing the image +on the SD card. Additionally, you also need some extra packages in order to get +rakudobrew, and to install Perl 6 itself. For this, we use the package manager +bundled with raspbian, `apt`: + +[source] +---- +# apt update +# apt upgrade +---- + +This will update the package lists, and then upgrade all outdated packages to +their newest versions. You should do this at least once a week to make sure +your system stays up to date. + +Once the upgrades are finished, you can install some new packages which are +needed later on in this tutorial: + +[source] +---- +# apt install git build-essential +---- + +`git` is required to get the rakudobrew repository and is also used by +rakudobrew itself to get the sources needed to build Perl 6 and to install zef. +The `build-essential` package comes with all sorts of tools to build software, +which is required to build Perl 6. + +== Installing Perl 6 + +Now, we've got a working Raspberry Pi installation. We can start doing things +with it, such as playing around with Perl 6. + +=== Setting up Rakudobrew + +Rakudobrew is a nice tool to manage Perl 6 installations on your system. It can +also install `zef` for you, so you don't have to deal with this manually. This +is all documented on the repository's `README.md` file as well, but I'll +explain it here too. I do make a few small tweaks here and there to match my +preferred setup more closely. + +Clone the repository to your system, and add it to your `$PATH` to be able to +use the scripts bundled with it: + +[source] +---- +$ mkdir -p ~/.local/var +$ git clone https://github.com/tadzik/rakudobrew.git ~/.local/var/rakudobrew +$ export PATH=${HOME}/.local/var/rakudobrew/bin:$PATH +$ hash -r +---- + +The `hash -r` call will rehash your PATH, so you can tab-complete `rakudobrew`. +Next, initialize rakudobrew: + +[source] +---- +$ rakudobrew init +---- + +This will give you a notification to automatically load rakudobrew next time. +It is advised you follow that message, so you won't have to do it manually each +time you log in to the system. + +=== Installing Perl 6 with MoarVM backend + +Now that rakudobrew is installed and available to use, it's time to make use of +it to install Perl 6. + +[source] +---- +$ rakudobrew build moar +---- + +=== Installing zef, the module manager + +Getting zef to work isn't much harder than installing Perl 6, but its a lot +faster. You can have rakudobrew take care of this too: + +[source] +---- +$ rakudobrew build zef +---- + +== Final words + +And that should be it, you now have a working Perl 6 installation with the zef +module manager to take care of installing and upgrading modules. Now you just +need to come up with a nice project to work on to start using and learning the +wonders of Perl 6. + +If you need any help on getting started, try the `#perl6` IRC channel on +Freenode, or check out some of the Perl 6 documentation and introduction sites: + +- https://docs.perl6.org/ +- http://perl6intro.com/ + +For starting projects that are easy to start with and can bring quick results, +consider making an IRC bot using +https://github.com/zoffixznet/perl6-IRC-Client[`IRC::Client`], or a small web +application using https://github.com/Bailador/Bailador[`Bailador`]. diff --git a/_posts/2017-12-17-on-cloudflare.adoc b/_posts/2017-12-17-on-cloudflare.adoc new file mode 100644 index 0000000..8d730a7 --- /dev/null +++ b/_posts/2017-12-17-on-cloudflare.adoc @@ -0,0 +1,128 @@ +--- +date: 2017-12-17 10:13:26 +tags: Article Harmful Cloudflare +description: > + Cloudflare is a threat to online security and privacy. I am not the first on + to address this issue, and I probably will not be the last either. Sadly, + people still seem to be very uninformed as to what issues Cloudflare actually + solves, or introduces. +--- += On Cloudflare +:toc: + +== Foreword +Cloudflare is a threat to online security and privacy. I am not the first on to +address this issue, and I probably will not be the last either. Sadly, people +still seem to be very uninformed as to what issues Cloudflare actually poses. +There also seems to be a big misconception about the benefits provided by using +Cloudflare. I would suggest reading the +http://cryto.net/~joepie91/blog/2016/07/14/cloudflare-we-have-a-problem/[article +on Cloudflare by joepie91] for a more thorough look at Cloudflare. + +If anyone is using Cloudflare, please tell them to stop doing it. Link them to +this page or any of the articles referenced here. Cloudflare is harmful to your +visitors, and if you do not care about them, they will stop caring about you +too. + +== A literal MITM attack +Cloudflare poses a huge risk by completely breaking the TLS/SSL chain used by +browsers by setting itself up as a +https://en.wikipedia.org/wiki/Man-in-the-middle_attack[man in the middle]. +Cloudflare doesn't do actual DDoS protection, they just make the request to the +origin server for you. Once they have received the data, they decrypt it and +re-encrypts it with their own certificate. This means that Cloudflare has +access to all requests in plain text and can optionally modify the data you +see. TLS/SSL is meant to prevent this very issue, but Cloudflare seems to care +very little. + +If we would consider Cloudflare to be a benevolent entity and surely never +modify any data ever, this is still an issue. Much data can be mined from the +plain text communications between you and the origin server. This data can be +used for all kinds of purposes. It is not uncommon for the USA government to +request a massive amount of surveillance information from companies without the +companies being able to speak up about it due to a gag order. This has become +clear once more by the +https://whispersystems.org/bigbrother/eastern-virginia-grand-jury/[subpoena on +Signal]. It should be clear to anyone that end-to-end encryption has to be a +standard and implemented properly. Cloudflare goes out of its way to break this +implementation. + +=== Cloudbleed +The danger of their MITM style of operation was shown be the +https://en.wikipedia.org/wiki/Cloudbleed[Cloudbleed] vulnerability. It also +shows that they make use of their MITM position to scan the data your site and +a visitor are exchanging. This includes private data, such as passwords. + +Even if you have an SSL connection to Cloudflare, they still decrypt it on +their end. They then serve the content under their own certificate. This makes +it look to the visitor like everything is secure, the browser says so after +all. But in reality, they don't have a secure connection to your server. They +only have one up to Cloudflare, and when it reaches Cloudflare, they decrypt it +and re-encrypt it using your certificate again. If you use one, of course, +otherwise they'll pass it on in plaintext back to your server, which is even +more dangerous. Whether or not you do, the content exists in plaintext on +Cloudflare's servers, which is not what you want, if you truly care about +security. + +== Eliminating your privacy +If Cloudflare were to fix their MITM behavior, the privacy problem would not +be solved all of a sudden. There are more questionable practices in use by +Cloudflare. + +People who are using a VPN or an anonimization service such as Tor are usually +greeted by a warning from Cloudflare. Let's not talk about this warning being +incorrect about the reason behind the user receiving the warning, but instead +about the methodology used to "pass" this "warning". Cloudflare presents you +with a page that requires you to solve a reCaptcha puzzle, which is hosted by a +well known third party that tries to harm your privacy as much as possible, +Google. If you do not wish to have Google tracking you all the time, you will +not be able to solve these puzzles, and in effect, unable to access the site +you were visiting. It is also interesting to note that this reCaptcha system is +sometimes broken if your browser does not identify itself as one of the regular +mainstream browsers such as Firefox or Chrome. + +Some site administrators disable this specific check. However, this still means +all your requests are logged by another third party, namely Cloudflare itself. +As noted in _A literal MITM attack_, this data is still very interesting to +some parties. And do not fool yourself: meta data is still very worthwhile and +can tell a huge amount of information about a person. + +=== Forcing JavaScript +This issue generally does not concern many people, as most people online +nowadays use a big mainstream browser with JavaScript enabled. However, there +are still people, services and applications that do not use JavaScript. This +makes sites unavailable when they are in the "under attack" mode by Cloudflare. +This will run a check sending Cloudflare your browser information before +deciding whether you are allowed to access the website. This is yet another +privacy issue, but at the same time, a usability issue. It makes your site +unavailable to people who simply do not wish to use JavaScript or people who +are currently limited to a browser with no JavaScript support. + +It is also common for Cloudflare to +http://www.tedunangst.com/flak/post/cloudflare-and-rss[Break RSS readers] by +presenting them with this check. This check is often presented to common user +agents used by services and programs. Since these do not include a big +JavaScript engine, there is no way for them to pass the test. + +== False advertising +=== DDoS protection +Cloudflare is hailed by many as a gratis DDoS protection service, and they +advertise themselves as such. However, Cloudflare does not offer DDoS +protection, they simply act as a pin cushion to soak the hit. Real DDoS +protection works by analyzing traffic, spotting unusual patterns and blocking +these requests. If they were to offer real DDoS protection like this, they +would be able to tunnel TLS/SSL traffic straight to the origin server, thereby +not breaking the TLS/SSL chain as they do right now. + +It should also be noted that this gratis "protection" truly gratis either. If +your site gets attacked for long enough, or for enough times in a short enough +time frame, you will be kicked off of the gratis plan and be moved onto the +"business" plan. This requires you to pay $200 per month for a service that does +not do what it is advertised to do. If you do not go to the business plan, you will +have about the same protection as you would have without it, but with the +addition of ruining the privacy and security of your visitors. + +=== Faster page loads +This is very well explained on joepie91's article under the heading _But The +Speed! The Speed!_. As such, I will refer to his article instead of +repeating him here. diff --git a/_posts/2017-12-21-funding-yourself-as-free-software-developer.adoc b/_posts/2017-12-21-funding-yourself-as-free-software-developer.adoc new file mode 100644 index 0000000..d292790 --- /dev/null +++ b/_posts/2017-12-21-funding-yourself-as-free-software-developer.adoc @@ -0,0 +1,231 @@ +--- +title: Funding Yourself As A Free Software Developer +date: 2017-12-21 05:29:26 +tags: Article FreeSoftware Development Funding +description: > + An overview of multiple funding platforms, with pros and cons, from the + perspective of a free software developer. It's intent is to help others find + a possible form of income while doing what they love, and what I consider is + immensely important for society. +--- += Funding Yourself As A Free Software Developer +:toc: preamble + +I've been meaning to spend more time on developing free software, helping out +new users on IRC and writing more tutorials to get others started. All of these +cost time, and time is money - so I've set out to set up donation accounts. +In the hopes of helping other developers who struggle to fund their work, I've +written up this article to talk about my experience. This is a living +document! As you explore this yourself, please send me your thoughts on each +platform and turn me on to interesting platforms I missed. + +I'll be focussing on platforms allowing for recurring donations, as these are +more useful for procuring a stable income. + +== Platforms +=== BountySource +[WARNING] +==== +- Requires 3rd-party link:/articles/on-cloudflare/[Cloudflare]-hosted + JavaScript sources to function. +==== + +BountySource lets people donate money towards an issue on Github your projects. +Once an issue gets fixed, you can claim the "bounty" that was on this issue. +This can also help in making clear which issue you should aim for next, and +can increase interest in contributors for your project. + +There's also BountySource Salt, which is a recurring donation platform. +Projects or teams can use this to gain monthly income to sustain the +development of their project(s). + +Support for this platform is offered through the IRC channel +https://kiwiirc.com/client/chat.freenode.net:+6697/#bountysource[`#bountysource` +on Freenode]. + +The BountySource platform itself is also free software, and the source code +for it can be found https://github.com/bountysource/core[on github]. + +You can find BountySource at https://www.bountysource.com/. + +=== LiberaPay +This service seems to be completely free as in freedom. They even +https://github.com/liberapay/liberapay.com[publish their source on GitHub]. +Their own funding comes through donations on their own platform, instead of +taking a cut of each donation like most other services. + +It's possible to connect other accounts to your LiberaPay account. While this +feature in general is pretty common, they allow you to link to sites which are +interesting to show as developer, such as GitHub, GitLab, and BitBucket. They +also let you link to a Mastodon account, if you have one. + +To let people know you're accepting donations through LiberaPay, you can use +one of the widgets they make available for you. This will show a donate button +which will link to you profile. Do note, this is not a regular HTML button or +cleverly implemented anchor tag, but a JavaScript-based button. + +Another thing LiberaPay lacks is a rewards system. Most other platforms allow +you to set reward tiers, which allow you to give certain benefits to donors. + +You can find Liberapay at https://liberapay.com/. + +=== MakerSupport +[WARNING] +==== +- The site requires a 3rd-party hosted jQuery. +- You have to solve a Google reCaptcha in order to register a new account. +==== + +MakerSupport seems to be another option, aimed at content creators who might +need freedom of speech more than others. It seems to be less focused on +software development, as you cannot link to any of the major git hosting +platforms. + +There are options here to set up "tiers" for your donors; which is a convenient +way to provide them with perks for their support. For a free software +developer, this might be something like access to more direct support from the +developer. + +Sadly, registration wasn't as smooth as most other platforms. My preferred +username, "tyil" is too short. There's no indication of the requirements of any +of the fields, you just get a popup on submission of the form saying a field is +wrong. + +Additionally, the registration form requires some 3rd-party JavaScript to work, +and a Google reCaptcha to be solved in order to get the submit button to show +up. As I have set up uMatrix in my browser, this cost me some extra time to +finish registration. + +Setting a profile image proved to be a little harder. First off, I'm still +using uMatrix so I had to allow a 3rd-party (Amazon, in this case) XHR +requests. Secondly, their error when uploading a "wrong" format is also not +very user friendly, as it won't give you any details on why it's disallowed, +nor what images are allowed instead. + +[NOTE] +==== +It seems they check the extension of the uploaded image's filename. As far as I +can tell, you're allowed to upload files that end with `.jpg` and `.png`. +==== + +You can find MakerSupport at https://www.makersupport.com/. + +=== Patreon +[WARNING] +==== +- Requires 3rd-party link:/articles/on-cloudflare[Cloudflare]-hosted + JavaScript sources to function. +- You have to solve a Google reCaptcha in order to register a new account. +==== + +Patreon is possibly the most famous donation-based funding platform available +right now. Its popularity is a good thing, since this means there's probably +many donors already using this platform. + +At Patreon, you can set up so-called goals. Goals are the thing I haven't found +with other funding platforms. It allows you to set a goal for an amount of +money, and add a reward to this. This way, you can inform your donors you will +be creating a certain kind of content once a one-time goal has been reached. +Basically, you can show your donors what you're going to do with the money +they're donating to you. + +Another interesting thing that I haven't seen on other platforms is the option +to charge donors per creation, instead of per month. While this may seem less +fitting for software developers (unless you want to get paid per commit, I +guess), it's an interesting feature that's pretty unique. If you publish many +tutorials, guides or other posts, this might fit you very well. + +You can link your account to other services, similarly to other platforms, but +it seems to only allow you to be linked with proprietary social media +platforms. + +You can find Patreon at https://www.patreon.com/home. + +=== (Dis)honorable mentions +==== Hatreon +I've included this because I found people talking about it on IRC. However, it +seems to be nothing more than a joke that's gone too far. Its main reason for +existing seems to be to get away from the political correctness found with +earlier crowdfunding platforms, yet their site is invite-only, so those who are +actually interested can't even use it. It seems that pledging is currently +disabled as well, and has been for at least 10 days. + +== But that's not all +Just setting up an account on a funding platform isn't enough. There's more to +keeping a healthy and happy supporter base. + +=== Spread awareness of your work +Whether you're writing articles or publishing new releases of projects, tell +the world you're doing whatever it is you're doing. If nobody knows about your +project, they won't be able to give any kind of appreciation for it. Use social +media outlets, public forums, mailing lists, anything! Tell them what you made, +why it's useful and how they could use it to improve their digital life. + +[WARNING] +==== +Ofcourse, don't spam it to unrelated communication channels. This will only +backfire. +==== + +=== Using the rewards system +On the platforms that support a rewards system, make use of it. There's some +little things you can do that go a long way with your supporters. For instance, +you can offer things like stickers to donors that donate a certain amount of +money to you. These are reasonably cheap to produce and ship, and many people +like these. + +Another idea that seems to strike well with donors is having a way to talk with +the person they're supporting directly. This can be done by giving them access +to an IRC channel for you and your donors. You can use another platform for +this, but most free software enthousiasts are already on IRC, and there's few +real-time communication alternatives that they're already using. + +=== Don't stick to a single platform +There's multiple platforms out there, use them! Not all of them have the same +userbase, and you can reach more people by giving them more options to work +with. + +=== Let people know you're accepting donations +If people don't know you're even accepting donations, chances are pretty high +you won't get any. Or if it's too hard to figure out how to donate to you, +people will simply not take the effort. Make sure people can easily find out +that you're accepting donations, and how to donate to you. + +=== Show what you're doing with donation money +Have a page with information about what you're using with the money. This can +be as simple as just saying you pay the rent and buy food with it. Most donors +don't mind too much what you're doing with the money they donate to you, but a +few do appreciate having this information available to them. + +It can be as simple as adding a `/donate` link to your site where you explain +how to donate to you, and what you do with the donation money. + +[WARNING] +==== +Don't let it turn into an annoying advertisement though, this will surely have +an opposite effect. +==== + +== Further reading +There's more places to go for tips and tricks in getting funds to sustain your +free software development work. I've listed a couple of these here for those +interested. + +- https://wiki.snowdrift.coop/market-research/other-crowdfunding[snowdrift.coop wiki on crowdfunding/fundraising services] +- https://github.com/nayafia/lemonade-stand[A handy guide to financial support for open source] + +== RFC +I'd love to receive feedback on this, as I think being able to get donations +easily for the work free software developers put in to their projects is +important. + +Getting to know more platforms and giving them a small write-up should help out +other developers like me looking for the best platform for their use case. I'd +also like to hear from developers already using a platform, to extend this +article with more useful information on how to successfully get donors for +their work. + +If you want to contact me, do take a look at the link:/[Contact] section, and +let me know about your experiences with funding. + +And if you liked this post, consider link:/support/[donating] ;) diff --git a/_posts/2018-02-05-why-perl6.adoc b/_posts/2018-02-05-why-perl6.adoc new file mode 100644 index 0000000..f482901 --- /dev/null +++ b/_posts/2018-02-05-why-perl6.adoc @@ -0,0 +1,280 @@ +--- +title: Why Perl 6? +date: 2018-02-05 18:22:20 +tags: Article Perl6 +description: > + I've grown quite fond of Perl 6 the more I learn about it, yet the general + developer community still seems to think Perl is a dirty word. In this + article, I will detail some of the features that make me like Perl 6, and why + I try to use it wherever possible. +--- += Why Perl 6? +:toc: preamble + +For about a year now, I've been working in Perl 6. Telling this to other people +often brings about some confused faces. I've grown quite fond of Perl 6 the +more I learn about it, yet the general developer community still seems to think +Perl is a dirty word. In this article, I will detail some of the features that +make me like Perl 6, and why I try to use it wherever possible. + +== Hassle-free command line arguments +Whet creating an application, you usually want to be able to specify some +arguments at runtime. Most times this happens using command line arguments or +options. Perl 6 allows you to specify these in the +https://docs.perl6.org/language/functions#index-entry-MAIN[`MAIN`] subroutine +signature. + +For instance, if I want the application to accept two string arguments, I can +do it as easy as this: + +[source,perl6] +---- +sub MAIN ( + Str $arg-one, + Str $arg-two, +) { + ... +} +---- + +Now, if you wanted to add an option like `--output=/path/to/file`, you can do +it just like this: + +[source,perl6] +---- +sub MAIN ( + Str $arg-one, + Str $arg-two, + Str :$output, +) { + ... +} +---- + +By default, if there's a `MAIN` available in your Perl 6 program, but the +arguments or options supplied by the user are incorrect, it will display the +right way to invoke the command, called the +https://docs.perl6.org/language/functions#index-entry-USAGE[`USAGE`]. Ofcourse, +this message can be changed if you wish, but the default is quite good for most +use-cases. + +However, sometimes you want to add a little explanation to what the argument or +option is intended for. Just for a liitle bit of additional user friendliness. + +Fear not, for this is also already covered by the defaults. In Perl, there was +POD to document your code. In Perl 6, we have +https://docs.perl6.org/language/glossary#index-entry-POD[POD] as well. And +these comments can be inspected at runtime to provide the user some +information. And that's exactly what the default `USAGE` also does. So if you +want to add some helpful comments to the arguments or the program itself, +simply add the comments where you want them: + +[source,perl6] +---- +#| This is a sample program, just to showcase the awesome stuff available in +#| Perl 6. +sub MAIN ( + Str $arg-one, #= Just a random argument + Str $arg-two, #= Yet another argument used for showcasing + Str :$output, #= Last but not least, an option which allows for a value +) { + ... +} +---- + +== Unicode +What if you could support all languages with a single implementation? That's +where unicode comes in. And Perl 6 currently has the best support for Unicode +out of all programming languages available. Its only real competitor seems to +be Swift (at the time of writing this). + +But not just for handling strings, Perl 6 uses unicode as a core language +feature. This means you can use them in your source code as well. And that +opens up some nice possibilities. Using the right unicode characters allows you +to write cleaner and more concise code, reducing the cognitive load while +trying to understand the program. + +For instance, if you're trying to do any kind of math, you can just use the +π character as a regular character. Or use the ² to get the square of a certain +number. This little piece is completely valid in Perl 6: + +[source,perl6] +---- +my $a = $r² ÷ π; +---- + +Now, if you're thinking "that looks neat, but how am I ever going to write +these?", do not worry. Most operating systems and many editors have tools to +let you input these. For instance, using `vim` with +https://github.com/vim-perl/vim-perl6[`vim-perl6`], you can just write "pi" and +hit space (or type any non-alphabetical character). + +But not everyone is using an OS or an editor that makes it easy. And for those +people, Perl 6 simply supports using +https://docs.perl6.org/language/unicode_ascii[ascii based operators]. The +previous block could also be written as follows: + +[source,perl6] +---- +my $a = $r ^ 2 / pi; +---- + +As unicode becomes more accepted, input methods will hopefully improve to make +input easier for everyone in the long run. Those who can already input it +easily don't have to wait for this future, Perl 6 already supports it. + +== Multithreading +Multi-core processors are virtually everywhere these days. Yet many programming +languages still don't support multithreaded application development natively, +if at all. In Perl 6, running something in a different thread is as easy as +wrapping it in a https://docs.perl6.org/routine/start[`start`] block: + +[source,perl6] +---- +start { + do-something(); +} +---- + +`start` returns a https://docs.perl6.org/type/Promise[`Promise`], which you can +store in a scalar variable just like any other object. You can check on whether +the `Promise` has completed already and check whether it died, for instance. + +Other aspects which can often be spread over multiple threads are loops or +maps. For instance, consider the following +https://docs.perl6.org/routine/map[map] function: + +[source,perl6] +---- +@cats.map: { + $^cat.pat; +} +---- + +This will pat each cat in turn, in the order they appear in the list. But you +can speed up the patting process by patting multiple cats at the same time. And +to get there, all you need to do is add a +https://docs.perl6.org/routine/race[`race`]: + +[source,perl6] +---- +@cats.race.map: { + $^cat.pat; +} +---- + +This will attempt to pat the cats over multiple threads, speeding up the +process to pat all the cats. If the result of the pattings needs to be in the +same order as the patting order, you use +https://docs.perl6.org/routine/hyper[`hyper`] instead of `race`: + +[source,perl6] +---- +@cats.hyper.map: { + $^cat.pat; +} +---- + +== Object orientation +Object oriented programming seems to be getting out of fashion with the new +generation of developers. But it's still in wide use, being taught at most +universities, and is often easy to explain to new developers as well. + +And Perl 6 has https://docs.perl6.org/language/classtut#index-entry-OOP[OO] +support built into its core: + +[source,perl6] +---- +class Foo +{ + has Str $some-field; + + method bar ( + Str $some-arg, + ) { + ... + } +} +---- + +You can also have +https://docs.perl6.org/language/glossary#index-entry-Multi-Dispatch[multi-dispatch] +methods on your classes, which are methods with the same names, but accepting +different arguments or argument types. For instance: + +[source,perl6] +---- +class Foo +{ + multi method bar ( + Str $some-arg, + ) { + ... + } + + multi method bar ( + Int $some-arg, + ) { + ... + } +} +---- + +Which method is being used will be decided by the type of argument is being +passed in, in this case either a https://docs.perl6.org/type/Str[`Str`] or an +https://docs.perl6.org/type/Int[`Int`]. + +== Functional programming +Whilst OO is considered being old more and more, functional programming is +gaining ground. And this paradigm is fully supported in the core of Perl 6 as +well. You've seen the `map` example already while patting cats earlier, for +instance. + +But there's much more on the functional playing field, such as the +https://docs.perl6.org/routine/==%3E[`=\=>`] operator, known as the +https://docs.perl6.org/language/operators#infix_==%3E[feed operator]. It simply +passed the output of a statement as the last argument to the next statement: + +[source,perl6] +---- +@grumpy-cats + ==> feed() + ==> pat() + ==> snuggle() + ==> my @happy-cats; +---- + +This will take the `@grumpy-cats`, feed them, pat them, snuggle them and put +the result into `@happy-cats`. You could've chained the calls using a `.` +instead, and Perl 6 allows you to do this too. But the `=\=>` looks much more +readable to me, which is why I prefer using this instead. + +I'm still exploring the functional programming field myself, but these few +things have made me happy exploring it. + +== Community +(Almost) last, but certainly not least, the Perl 6 community is amazing. It's +been the friendliest bunch I've been with, both on IRC, their mailing lists and +in real life. Everyone is welcoming, and they try to help you whenever they +can. + +Community is important to help you out whenever you get stuck for whatever +reason. A friendly community is the best you can get here to keep you a happy +developer yourself as well. + +== Other little aspects +There's a few neat things I can do in Perl 6 that I can't do in (most) other +languages, but aren't important enough to warrant a large section to show them +off. + +=== Dashes in names +You can use dashes in names: Things like `my $foo-bar` is valid, just like +`method foo-bar`. It's nothing big on itself, but I've found it makes reading +code much more enjoyable than pascalCase, CamelCase or snake_case. + +=== Gradual typing +You don't *need* to use types in Perl 6. But when you want to use them (for +making use of multi-dispatch, for example), you can just start using them. If +types are added, the compiler will make sure the types are correct. If not, you +can always do them yourself (but why would you, when the compiler can do a +better job for free). diff --git a/_posts/2018-03-20-perl6-introduction-to-application-programming.adoc b/_posts/2018-03-20-perl6-introduction-to-application-programming.adoc new file mode 100644 index 0000000..6759d80 --- /dev/null +++ b/_posts/2018-03-20-perl6-introduction-to-application-programming.adoc @@ -0,0 +1,784 @@ +--- +title: "Perl 6 - Introduction to application programming" +date: 2018-03-20 11:08:00 +tags: Tutorial Perl6 Assixt GTK tutorial programming +layout: post +authors: + - ["Patrick Spek", "https://tyil.nl"] +--- += Perl 6 - Introduction to application programming +:toc: preamble + +In this tutorial, I'll be guiding you through creating a simple application in +Perl 6. If you don't have Perl 6 installed yet, get the +http://rakudo.org/how-to-get-rakudo/[Rakudo Star] distribution for your OS. +Alternatively, you can use the https://hub.docker.com/_/rakudo-star/[Docker +image]. + +The application itself will be a simple dice-roller. You give it a number of +dice to roll, and the number of sides the die has. We'll start off by creating +it as a console application, then work to make it a GUI as well with the +`GTK::Simple` module. + +== Preparation +First, you'll want to install the libgtk headers. How to get these depends on +your distro of choice. For Debian-based systems, which includes Ubuntu and +derivatives, this command would be the following `apt` invocation: + +[source] +---- +$ apt install libgtk-3-dev +---- + +For other distros, please consult your documentation. + +To ease up module/application building, I'll use `App::Assixt`. This module +eases up on common tasks required for building other modules or applications. +So we'll start by installing this module through `zef`. + +[source] +---- +$ zef install App::Assixt +---- + +[NOTE] +==== +You may need to rehash your `$PATH` as well, which can be done using `hash -r` +on `bash`, or `rehash` for `zsh`. For other shells, consult your manual. +==== + +Next up, we can use `assixt` to create the new skeleton of our application, +with the `new` subcommand. This will ask for some user input, which will be +recorded in the `META6.json`, a json-formatted file to keep track of meta +information about the module. `assixt` should take care of this file for you, +so you never need to actually deal with it. + +[source] +---- +$ assixt new +---- + +=== assixt input +Since the `assixt new` command requires some input, I'll walk through these +options and explain how these would affect your eventual application. + +==== Name of the module +This is the name given to the module. This will be used for the directory name, +which by default in `assixt` will be `perl6-` prepended to a lower-case version +of the module name. If you ever wish to make a module that is to be shared in +the Perl 6 ecosystem, this should be unique across the entire ecosystem. If +you're interested in some guidelines, the +https://pause.perl.org/pause/query?ACTION=pause_namingmodules[PAUSE guidelines] +seem to apply pretty well to Perl 6 as well. + +For this application, we'll use `Local::App::Dicer`, but you can use whatever +name you'd prefer here. + +==== Your name +Your name. This will be used as the author's name in the `META6.json`. It is +used to find out who made it, in order to report issues (or words of praise, +of course). + +==== Your email address +Your email address. Like your name, it will be used in case someone has to +contact you in regards off the module. + +==== Perl 6 version +This defaults to `c` right now, and you can just hit enter to accept it. In the +future, there will be a Perl 6.d available as well, in which case you can use +this to indicate you want to use the newer features introduced in 6.d. This is +not the case yet, so you just want to go with the default `c` value here. + +==== Module description +A short description of your module, preferably a single sentence. This is +useful to people wondering what the module is for, and module managers can show +to the user. + +==== License key +This indicates the license under which your module is distributed. This +defaults to `GPL-3.0`, which I strongly recommend to use. The de-facto +default seems to be `Artistic-2.0`, which is also used for Perl 6 itself. + +This identifier is based on the https://spdx.org/licenses/[SPDX license list]. +Anything not mentioned in this list is not acceptable. #TODO Clarify why + +== Writing your first test +With the creation of the directory structure and metadata being taken care of +by `assixt`, we can now start on writing things. Tests are not mandatory, but +are a great tool for quickly checking if everything works. If you make larger +applications, it really helps not having to manually test anything. Another +benefit is that you can quickly see if your changes, or those of someone else, +break anything. + +Creating the base template for tests, `assixt` can help you out again: `assixt +touch` can create templates in the right location, so you don't have to deal +with it. In this case we want to create a test, which we'll call "basic". + +[source] +---- +$ assixt touch test basic +---- + +This will create the file `t/basic.t` in your module directory. Its contents +will look as follows: + +[source,perl6] +---- +#! /usr/bin/env perl6 + +use v6.c; + +use Test; + +ok True; + +done-testing; + +# vim: ft=perl6 +---- + +The only test it has right now is `ok True`, which will always pass testing. We +will change that line into something more usable for this application: + +[source,perl6] +---- +use Local::App::Dicer; + +plan 2; + +subtest "Legal rolls", { + plan 50; + + for 1..50 { + ok 1 ≤ roll($_) ≤ $_, "Rolls between 1 and $_"; + } +} + +subtest "Illegal rolls", { + plan 3; + + throws-like { roll(0) }, X::TypeCheck::Binding::Parameter, "Zero is not accepted"; + throws-like { roll(-1) }, X::TypeCheck::Binding::Parameter, "Negative rolls are not accepted"; + throws-like { roll(1.5) }, X::TypeCheck::Binding::Parameter, "Can't roll half sides"; +} +---- + +[NOTE] +==== +Perl 6 allows mathematical characters to make your code more concise, as with +the ≤ in the above block. If you use http://www.vim.org/[vim], you can make use +of the https://github.com/vim-perl/vim-perl6[vim-perl6] plugin, which has an +option to change the longer, ascii-based ops (in this case `\<=`) into the +shorter unicode based ops (in this case `≤`). This specific feature requires +`let g:perl6_unicode_abbrevs = 1` in your `vimrc` to be enabled with +`vim-perl6`. + +If that's not an option, you can use a +https://en.wikipedia.org/wiki/Compose_key[compose key]. If that is not viable +either, you can also stick to using the ascii-based ops. Perl 6 supports both +of them. +==== + +This will run 53 tests, split up in two +https://docs.perl6.org/language/testing#Grouping_tests[subtests]. Subtests are +used to logically group your tests. In this case, the calls that are correct +are in one subtest, the calls that should be rejected are in another. + +The `plan` keywords indicate how many tests should be run. This will help spot +errors in case your expectations were not matched. For more information on +testing, check out https://docs.perl6.org/language/testing[the Perl 6 docs on +testing]. + +We're making use of two test routines, `ok` and `throws-like`. `ok` is a +simple test: if the given statement is truthy, the test succeeds. The other +one, `throws-like`, might require some more explanation. The first argument it +expects is a code block, hence the `{ }`. Inside this block, you can run any +code you want. In this case, we run code that we know shouldn't work. The +second argument is the exception it should throw. The test succeeds if the +right exception is thrown. Both `ok` and `throws-like` accept a descriptive +string as optional last argument. + +=== Running the tests +A test is useless if you can't easily run it. For this, the `prove` utility +exists. You can use `assixt test` to run these tests properly as well, saving +you from having to manually type out the full `prove` command with options. + +[source] +---- +$ assixt test +---- + +You might notice the tests are currently failing, which is correct. The +`Local::App::Dicer` module doesn't exist yet to test against. We'll be working +on that next. + +[NOTE] +==== +For those interested, the command run by `assixt test` is `prove -e "perl6 +-Ilib" t`. This will include the `lib` directory into the `PERL6PATH` to be +able to access the libraries we'll be making. The `t` argument specifies the +directory containing the tests. +==== + +== Creating the library +Again, let's start with a `assixt` command to create the base template. This +time, instead of `touch test`, we'll use `touch lib`. + +[source] +---- +$ assixt touch unit Local::App::Dicer +---- + +This will generate a template file at `lib/Local/App/Dicer.pm6` which some +defaults set. The file will look like this. + +[source,perl6] +---- +#! /usr/bin/env false + +use v6.c; + +unit module Local::App::Dicer; +---- + +The first line is a https://en.wikipedia.org/wiki/Shebang_(Unix)[shebang]. It +informs the shell what to do when you try to run the file as an executable +program. In this case, it will run `false`, which immediately exits with a +non-success code. This file needs to be run as a Perl 6 module file, and +running it as a standalone file is an error. + +The `use v6.c` line indicates what version of Perl 6 should be used, and is +taken from the `META6.json`, which was generated with `assixt new`. The last +line informs the name of this module, which is `Local::App::Dicer`. Beneath +this, we can add subroutines, which can be exported. These can then be accessed +from other Perl 6 files that `use` this module. + +=== Creating the `roll` subroutine +Since we want to be able to `roll` a die, we'll create a subroutine to do +exactly that. Let's start with the signature, which tells the compiler the name +of the subroutine, which arguments it accepts, their types and what type the +subroutine will return. + +[TIP] +==== +Perl 6 is gradually typed, so all type information is optional. The subroutine +arguments are optional too, but you will rarely want a subroutine that doesn't +have an argument list. +==== + +[source,perl6] +---- +sub roll($sides) is export +{ + $sides +} +---- + +Let's break this down. + +- `sub` informs the compiler we're going to create a subroutine. +- `roll` is the name of the subroutine we're going to create. +- `$sides` defines an argument used by the subroutine. +- `is export` tells the compiler that this subroutine is to be exported. This + allows access to the subroutine to another program that imports this module + through a `use`. +- `{ $sides }` is the subroutine body. In Perl 6, the last statement is also + the return value in a code block, thus this returns the value of $sides. A + closing `;` is also not required for the last statement in a block. + +If you run `assixt test` now, you can see it only fails 1/2 subtests: + +[source] +---- +# TODO: Add output of failing tests +---- + +Something is going right, but not all of it yet. The 3 tests to check for +illegal rolls are still failing, because there's no constraints on the input of +the subroutine. + +=== Adding constraints +The first constraint we'll add is to limit the value of `$sides` to an `Int:D`. +The first part of this constraint is common in many languages, the `Int` part. +The `:D` requires the argument to be **defined**. This forces an actual +existing instance of `Int`, not a `Nil` or undefined value. + +[source,perl6] +---- +sub roll(Int:D $sides) is export +---- + +Fractional input is no longer allowed, since an `Int` is always a round number. +But an `Int` is still allowed to be 0 or negative, which isn't possible in a +dice roll. Nearly every language will make you solve these two cases in the +subroutine body. But in Perl 6, you can add another constraint in the signature +that checks for exactly that: + +[source,perl6] +---- +sub roll(Int:D $sides where $sides > 0) is export +---- + +The `where` part specifies additional constraints, in this case `$sides > 0`. +So now, only round numbers larger than 0 are allowed. If you run `assixt test` +again, you should see all tests passing, indicating that all illegal rolls are +now correctly disallowed. + +=== Returning a random number +So now that we can be sure that the input is always correct, we can start on +making the output more random. In Perl 6, you can take a number and call +`.rand` on it, to get a random number between 0 and the value of the number you +called it on. This in turn can be rounded up to get a number ranging from 1 to +the value of the number you called `.rand` on. These two method calls can also +be changed to yield concise code: + +[source,perl6] +---- +sub roll(Int:D $sides where $sides > 0) is export +{ + $sides.rand.ceiling +} +---- + +That's all we need from the library itself. Now we can start on making a usable +program out of it. + +== Adding a console interface +First off, a console interface. `assixt` can `touch` a starting point for an +executable script as well, using `assixt touch bin`: + +[source] +---- +$ assixt touch bin dicer +---- + +This will create the file `bin/dicer` in your repository, with the following +template: + +[source,perl6] +---- +#! /usr/bin/env perl6 + +use v6.c; + +sub MAIN +{ + … +} +---- + +The program will run the `MAIN` sub by default. We want to slightly change this +`MAIN` signature though, since we want to accept user input. And it just so +happens that you can specify the command line parameters in the `MAIN` +signature in Perl 6. This lets us add constraints to the parameters and give +them better names with next to no effort. We want to accept two numbers, one +for the number of dice, and one for the number of sides per die: + +[source,perl6] +---- +sub MAIN(Int:D $dice, Int:D $sides where { $dice > 0 && $sides > 0 }) +---- + +Here we see the `where` applying constraints again. If you try running this +program in its current state, you'll have to run the following: + +[source] +---- +$ perl6 -Ilib bin/dicer +Usage: + bin/dicer +---- + +This will return a list of all possible ways to invoke the program. There's one +slight problem right now. The usage description does not inform the user that +both arguments need to be larger than 0. We'll take care of that in a moment. +First we'll make this part work the way we want. + +To do that, let's add a `use` statement to our `lib` directory, and call the +`roll` function we created earlier. The `bin/dicer` file will come to look as +follows: + +[source,perl6] +---- +#! /usr/bin/env perl6 + +use v6.c; + +use Local::App::Dicer; + +sub MAIN(Int:D $dice, Int:D $sides where { $dice > 0 && $sides > 0 }) +{ + say $dice × roll($sides) +} +---- + +[NOTE] +==== +Just like the `≤` character, Perl 6 allows to use the proper multiplication +character `×` (this is not the letter `x`!). You can use the more widely known +`*` for multiplication as well. +==== + +If you run the program with the arguments `2` and `20` now, you'll get a random +number between 2 and 40, just like we expect: + +[source] +---- +$ perl6 -Ilib bin/dicer 2 20 +18 +---- + +=== The usage output +Now, we still have the trouble of illegal number input not clearly telling +what's wrong. We can do a neat trick with +https://docs.perl6.org/language/functions#index-entry-USAGE[the USAGE sub] to +achieve this. Perl 6 allows a subroutine with the name `USAGE` to be defined, +overriding the default behaviour. + +Using this, we can generate a friendlier message informing the user what they +need to supply more clearly. The `USAGE` sub would look like this: + +[source,perl6] +---- +sub USAGE +{ + say "Dicer requires two positive, round numbers as arguments." +} +---- + +If you run the program with incorrect parameters now, it will show the text +from the `USAGE` subroutine. If the parameters are correct, it will run the +`MAIN` subroutine. + +You now have a working console application in Perl 6! + +== Making a simple GUI +But that's not all. Perl 6 has a module to create GUIs with the +https://www.gtk.org/[GTK library] as well. For this, we'll use the +http://modules.perl6.org/dist/GTK::Simple:github:perl6[`GTK::Simple`] module. + +You can add this module as a dependency to the `Local::App::Dicer` repository +with `assixt` as well, using the `depend` command. By default, this will also +install the dependency locally so you can use it immediately. + +[source] +---- +$ assixt depend GTK::Simple +---- + +=== Multi subs +Next, we could create another executable file and call it `dicer-gtk`. However, +I can also use this moment to introduce +https://docs.perl6.org/language/glossary#index-entry-multi-method[multi +methods]. These are subs with the same name, but differing signatures. If a +call to such a sub could potentially match multiple signatures, the most +specific one will be used. We will add another `MAIN` sub, which will be called +when `bin/dicer` is called with the `--gtk` parameter. + +We should also update the `USAGE` sub accordingly, of course. And while we're +at it, let's also include the `GTK::Simple` and `GTK::Simple::App` modules. The +first pulls in all the different GTK elements we will use later on, while the +latter pulls in the class for the base GTK application window. The updated +`MAIN`, `USAGE` and `use` parts will now look like this: + +[source,perl6] +---- +use Local::App::Dicer; +use GTK::Simple; +use GTK::Simple::App; + +multi sub MAIN(Int:D $dice, Int:D $sides where { $dice > 0 && $sides > 0 }) +{ + say $dice × roll($sides) +} + +multi sub MAIN(Bool:D :$gtk where $gtk == True) +{ + # TODO: Create the GTK version +} + +sub USAGE +{ + say "Launch Dicer as a GUI with --gtk, or supply two positive, round numbers as arguments."; +} +---- + +There's a new thing in a signature header here as well, `:$gtk`. The `:` in +front of it makes it a named argument, instead of a positional one. When used +in a `MAIN`, this will allow it to be used like a long-opt, thus as `--gtk`. +Its use in general subroutine signatures is explained in the next chapter. + +Running the application with `--gtk` gives no output now, because the body only +contains a comment. Let's fix that. + +=== Creating the window +First off, we require a `GTK::Simple::App` instance. This is the main window, +in which we'll be able to put elements such as buttons, labels, and input +fields. We can create the `GTK::Simple::App` as follows: + +[source,perl6] +---- +my GTK::Simple::App $app .= new(title => "Dicer"); +---- + +This one line brings in some new Perl 6 syntax, namely the `.=` operator. +There's also the use of a named argument in a regular subroutine. + +The `.=` operator performs a method on the variable on the left. In our case, +it will call the `new` subroutine, which creates a new instance of the +`GTK::Simple::App` class. This is commonly referred to as the **constructor**. + +The named argument list (`title \=> "Dicer"`) is another commonly used feature +in Perl 6. Any method can be given a non-positional, named parameter. This is +done by appending a `:` in front of the variable name in the sub signature. +This has already been used in our code, in `multi sub MAIN(Bool :$gtk where +$gtk == True)`. This has a couple of benefits, which are explained in the +https://docs.perl6.org/type/Signature#index-entry-positional_argument_%28Signature%29_named_argument_%28Signature%29[Perl +6 docs on signatures]. + +=== Creating the elements +Next up, we can create the elements we'd like to have visible in our +application window. We needed two inputs for the console version, so we'll +probably need two for the GUI version as well. Since we have two inputs, we +want labels for them. The roll itself will be performed on a button press. +Lastly, we will want another label to display the outcome. This brings us to 6 +elements in total: + +- 3 labels +- 2 entries +- 1 button + +[source,perl6] +---- +my GTK::Simple::Label $label-dice .= new(text => "Amount of dice"); +my GTK::Simple::Label $label-sides .= new(text => "Dice value"); +my GTK::Simple::Label $label-result .= new(text => ""); +my GTK::Simple::Entry $entry-dice .= new(text => 0); +my GTK::Simple::Entry $entry-sides .= new(text => 0); +my GTK::Simple::Button $button-roll .= new(label => "Roll!"); +---- + +This creates all elements we want to show to the user. + +=== Show the elements in the application window +Now that we have our elements, let's put them into the application window. +We'll need to put them into a layout as well. For this, we'll use a grid. The +`GTK::Simple::Grid` constructor takes pairs, with the key being a tuple +containing 4 elements, and the value containing the element you want to show. +The tuple's elements are the `x`, `y`, `w` and `h`, which are the x +coordinates, y coordinates, width and height respectively. + +This in turn takes us to the following statement: + +[source,perl6] +---- +$app.set-content( + GTK::Simple::Grid.new( + [0, 0, 1, 1] => $label-dice, + [1, 0, 1, 1] => $entry-dice, + [0, 1, 1, 1] => $label-sides, + [1, 1, 1, 1] => $entry-sides, + [0, 2, 2, 1] => $button-roll, + [0, 3, 2, 1] => $label-result, + ) +); +---- + +Put a `$app.run` beneath that, and try running `perl6 -Ilib bin/dicer --gtk`. +That should provide you with a GTK window with all the elements visible in the +position we want. To make it a little more appealing, we can add a +`border-width` to the `$app`, which adds a margin between the border of the +application window, and the grid inside the window. + +[source,perl6] +---- +$app.border-width = 20; +$app.run; +---- + +You may notice that there's no `()` after the `run` method call. In Perl 6, +these are optional if you're not supplying any arguments any way. + +=== Binding an action to the button +Now that we have a visible window, it's time to make the button perform an +action. The action we want to execute is to take the values from the two +inputs, roll the correct number of dice with the correct number of sides, and +present it to the user. + +The base code for binding an action to a button is to call `.clicked.tap` on it, +and provide it with a code block. This code will be executed whenever the +button is clicked. + +[source,perl6] +---- +$button-roll.clicked.tap: { +}; +---- + +You see we can also invoke a method using `:`, and then supplying its +arguments. This saves you the trouble of having to add additional `( )` around +the call, and in this case it would be annoying to have to deal with yet +another set of parens. + +Next, we give the code block something to actually perform: + +[source,perl6] +---- +$button-roll.clicked.tap: { + CATCH { + $label-result.text = "Can't roll with those numbers"; + } + + X::TypeCheck::Binding::Parameter.new.throw if $entry-dice.text.Int < 1; + + $label-result.text = ($entry-dice.text.Int × roll($entry-sides.text.Int)).Str; +}; +---- + +There's some new things in this block of code, so let's go over these. + +- `CATCH` is the block in which we'll end up if an exception is thrown in this + scope. `roll` will throw an exception if the parameters are wrong, and this + allows us to cleanly deal with that. +- `X::TypeCheck::Binding::Parameter.new.throw` throws a new exception of type + `X::TypeCheck::Binding::Parameter`. This is the same exception type as thrown + by `roll` if something is wrong. We need to check the number of dice manually + here, since `roll` doesn't take care of it, nor does any signature impose any + restrictions on the value of the entry box. +- `if` behind another statement. This is something Perl 6 allows, and in some + circumstances can result in cleaner code. It's used here because it improves + the readability of the code, and to show that it's possible. + +== The completed product +And with that, you should have a dice roller in Perl 6, with both a console and +GTK interface. Below you can find the complete, finished sourcefiles which you +should have by now. + +=== t/basic.t +[source,perl6] +---- +#! /usr/bin/env perl6 + +use v6.c; + +use Test; +use Local::App::Dicer; + +plan 2; + +subtest "Legal rolls", { + plan 50; + + for 1..50 { + ok 1 ≤ roll($_) ≤ $_, "Rolls between 1 and $_"; + } +} + +subtest "Illegal rolls", { + plan 3; + + throws-like { roll(0) }, X::TypeCheck::Binding::Parameter, "Zero is not accepted"; + throws-like { roll(-1) }, X::TypeCheck::Binding::Parameter, "Negative rolls are not accepted"; + throws-like { roll(1.5) }, X::TypeCheck::Binding::Parameter, "Can't roll half sides"; +} + +done-testing; + +# vim: ft=perl6 +---- + +=== lib/Local/App/Dicer.pm6 +[source,perl6] +---- +#! /usr/bin/env false + +use v6.c; + +unit module Local::App::Dicer; + +sub roll(Int:D $sides where $sides > 0) is export +{ + $sides.rand.ceiling; +} +---- + +=== bin/dicer +[source,perl6] +---- +#! /usr/bin/env perl6 + +use v6.c; + +use Local::App::Dicer; +use GTK::Simple; +use GTK::Simple::App; + +multi sub MAIN(Int:D $dice, Int:D $sides where { $dice > 0 && $sides > 0 }) +{ + say $dice × roll($sides) +} + +multi sub MAIN(Bool:D :$gtk where $gtk == True) +{ + my GTK::Simple::App $app .= new(title => "Dicer"); + my GTK::Simple::Label $label-dice .= new(text => "Number of dice"); + my GTK::Simple::Label $label-sides .= new(text => "Number of sides per die"); + my GTK::Simple::Label $label-result .= new(text => ""); + my GTK::Simple::Entry $entry-dice .= new(text => 0); + my GTK::Simple::Entry $entry-sides .= new(text => 0); + my GTK::Simple::Button $button-roll .= new(label => "Roll!"); + + $app.set-content( + GTK::Simple::Grid.new( + [0, 0, 1, 1] => $label-dice, + [1, 0, 1, 1] => $entry-dice, + [0, 1, 1, 1] => $label-sides, + [1, 1, 1, 1] => $entry-sides, + [0, 2, 2, 1] => $button-roll, + [0, 3, 2, 1] => $label-result, + ) + ); + + $button-roll.clicked.tap: { + CATCH { + $label-result.text = "Can't roll with those numbers"; + } + + X::TypeCheck::Binding::Parameter.new.throw if $entry-dice.text.Int < 1; + + $label-result.text = ($entry-dice.text.Int × roll($entry-sides.text.Int)).Str; + }; + + $app.border-width = 20; + + $app.run; +} + +sub USAGE +{ + say "Launch Dicer as a GUI with --gtk, or supply two positive, round numbers as arguments."; +} +---- + +== Installing your module +Now that you have a finished application, you probably want to install it as +well, so you can run it by calling `dicer` in your shell. For this, we'll be +using `zef`. + +To install a local module, tell `zef` to try and install the local directory +you're in: + +[source] +---- +$ zef install . +---- + +This will resolve the dependencies of the local module, and then install it. +You should now be able to run `dicer` from anywhere. + +[WARNING] +==== +With most shells, you have to "rehash" your `$PATH` as well. On `bash`, this is +done with `hash -r`, on `zsh` it's `rehash`. If you're using any other shell, +please consult the manual. +==== diff --git a/_posts/2018-05-07-sparrowdo-getting-started.adoc b/_posts/2018-05-07-sparrowdo-getting-started.adoc new file mode 100644 index 0000000..7164c6b --- /dev/null +++ b/_posts/2018-05-07-sparrowdo-getting-started.adoc @@ -0,0 +1,231 @@ +--- +date: 2018-05-07 14:04:43 +tags: Tutorial Tutorial Perl6 Sparrowdo GettingStarted +description: > + Nondescript +--- += Sparrowdo - Getting started +:toc: preamble + +https://github.com/melezhik/sparrowdo[Sparrowdo] is a Perl 6 project to +facilitate automatic configuration of systems. There's a +https://sparrowhub.org/[repository of useful modules] to make specific cases +easier to work with, but the +https://github.com/melezhik/sparrowdo/blob/master/core-dsl.md[Core DSL] can +already take care of many tasks. In this tutorial, I'll guide you through +setting up Sparrowdo, bootstrapping it onto your local system, writing a task +and running it. + +== Install Sparrowdo +Sparrowdo is a http://perl6.org/[Perl 6] project, so you'll need to have Perl 6 +installed. We'll also use the Perl 6 package manager +https://github.com/ugexe/zef/[zef] to install Sparrowdo itself. Luckily for us, +there's a stable distribution of Perl 6 with everything we need added to it, +called https://rakudo.org/files[Rakudo Star]. And to make it easier for +GNU+Linux users, I wrote a tool to fetch the latest Rakudo Star release, compile +it and install it, called https://github.com/Tyil/lonestar[LoneStar]. Since this +tutorial will aim at GNU+Linux users, I'll use that to install Perl 6. + +=== Installing Perl 6 with LoneStar +LoneStar is a Bash application to download, compile and set up Perl 6. It's a +standalone application, meaning you don't have to install it to your system. You +can just run it from the source directory. First, we'll have to get the source +directory, which we'll do using `git`. + +[source,sh] +---- +mkdir -p ~/.local/src +git clone https://github.com/tyil/lonestar.git ~/.local/src/lonestar +cd !$ +---- + +Now you have the LoneStar sources available in `~/.local/src/lonestar`. You can +run the application using `./bin/lonestar`. Running it, you'll get some help +output: + +[source] +---- +$ ./bin/lonestar +lonestar - Installation manager for Rakudo Star + +Usage: lonestar [arguments...] + +Actions: + help [action] + init [version=latest] + install [version=latest] + path [version=latest] + reinstall [version=latest] + upgrade +---- + +We'll be needing the `install` action to get Perl 6 installed, and the `init` +action to configure the `$PATH` environment variable. Depending on your +hardware, `install` may take a couple minutes as it will compile Rakudo Perl 6 +and install some base modules. You might want to grab a drink during this +period. + +[source] +---- +$ ./bin/lonestar install +$ eval $(./bin/lonestar init) +$ perl6 -v +This is Rakudo Star version 2018.04.1 built on MoarVM version 2018.04.1 +implementing Perl 6.c. +---- + +[NOTE] +==== +If there's a newer version available of Rakudo Star, the version numbers given +by `perl6 -v` will differ for you. +==== + +=== Installing Sparrowdo with zef +Now that you have Perl 6 available and installed, you can continue on using +`zef` to install Sparrowdo. `zef` is bundled with Rakudo Star, so you don't have +to do anything to get it working. + +[source,sh] +---- +zef install Sparrowdo +---- + +This will instruct `zef` to install Sparrowdo and all its dependencies. This can +take a couple minutes, again depending on the hardware of your machine. + +== Bootstrapping your system +The first step to working with Sparrowdo is bootstrapping the system you wish to +use it with. In this case, that'll be the local system. There's a `--bootstrap` +option to do this automatically. + +[source,sh] +---- +sparrowdo --bootstrap +---- + +[TIP] +==== +If you wish to bootstrap a remote system, you can use the `--host` option to +specify the system. For example: `sparrowdo --host=192.168.1.2 --bootstrap`. +==== + +Now your system is ready to be configured automatically using Sparrowdo! + +== Sparrowfiles +Sparrowfiles are the files that describe the tasks Sparrow should execute to +get you the configuration you want. They are valid Perl 6 code, and call the +subroutines (or _sparrowtasks_) that will handle the actual actions. By default, +when running `sparrowdo`, it will look for a file named `sparrowfile` in the +current directory. + +To make our sample, we'll create a new directory to work in, so we have clean +directory that can be shared easily. You can also keep this directory under +version control, so you can distribute the `sparrowfile` with all its templates. + +[TIP] +==== +If you just want to create an empty directory to test things in, without +"polluting" the rest of your system, just call `cd -- "$(mktemp -d)"`. This will +create a temporary directory and change the working directory to there. +==== + +I'll be using `~/.local/sparrowdo/local-dns` to work in, as I'll be setting up a +local dns cache with http://www.thekelleys.org.uk/dnsmasq/doc.html[dnsmasq] for +the sample code. + +=== Writing a `sparrowfile` +As noted in the previous paragraph, for the sake of a demo I'll guide you +through creating a `sparrowfile` to install and configure `dnsmasq` as a local +DNS cache. Using your favourite `$EDITOR`, write the following to `sparrowfile`: + +[source,perl6] +---- +package-install "dnsmasq"; +directory "/etc/dnsmasq.d"; +file-create "/etc/dnsmasq.conf", %(content => slurp "dnsmasq.conf"); +file-create "/etc/dnsmasq.d/resolv.conf", %(content => slurp "resolv.conf"); +service-start "dnsmasq"; +---- + +This `sparrowfile` will set up the following configuration for `dnsmasq`: + +- Install the `dnsmasq` package +- Create the `/etc/dnsmasq.d` directory in which we'll store configuration files + for `dnsmasq` +- Create the configuration files `dnsmasq.conf` at `/etc/dnsmasq.conf` +- Create the `resolv.conf` in the `dnsmasq.d` directory +- Start the `dnsmasq` service + +The configuration files will be created based on the configuration files in the +current directory. So for this to work, you'll need to also create the +appropriate configuration files. Let's start off with the main `dnsmasq` +configuration in `dnsmasq.conf`: + +[source,conf] +---- +listen-address=127.0.0.1 + +no-dhcp-interface= +resolv-file=/etc/dnsmasq.d/resolv.conf +---- + +This will make `dnsmasq` listen on the loopback interface, so it'll only be able +to be used by the local machine. Furthermore, DHCP functionality will be +disabled, and the upstream resolvers are read from `/etc/dnsmasq.d/resolv.conf`. +The contents of that file are as follows: + +[source,conf] +---- +nameserver 37.235.1.174 +nameserver 37.235.1.177 +---- + +These nameservers are part of the https://freedns.zone/en/[FreeDNS] project. You +can of course use whatever other DNS provider you want to use as your upstream +servers. Now, for `dnsmasq` to be used, you will also need to set your machine's +DNS resolvers to point to the `dnsmasq` service. This is defined in +`/etc/resolv.conf`, so lets append the following to our `sparrowfile` to set +that up. + +[source,conf] +---- +bash "chattr -i /etc/resolv.conf"; +file-delete "/etc/resolv.conf"; +file-create "/etc/resolv.conf", %(content => "nameserver 127.0.0.1"); +bash "chattr +i /etc/resolv.conf"; +---- + +This will remove the "immutable" attribute from `/etc/resolv.conf` if it's set. +Next it will remove the current `/etc/resolv.conf` and write out a new one which +only refers to the local machine as DNS resolver. This is to ensure an existing +`/etc/resolv.conf` gets recreated with the configuration we want. Finally, it +adds back the immutable attribute to the file, so other processes won't +overwrite it. + +=== Running the `sparrowfile` +To run the `sparrowfile` and get the setup you desire, run the `sparrowdo` +command with `--local_mode` and wait. + +[source] +---- +sparrowdo --local_mode +---- + +[NOTE] +==== +If you want to run this on a remote machine to configure that one instead, you +can use `--host=` instead of `--local_mode`. +==== + +You can check whether it actually worked by inspecting the files in +`/etc/dnsmasq.d` and your `/etc/resolv.conf`. The easiest way to check their +contents would be by using `cat`: + +[source] +---- +cat /etc/dnsmasq.d/dnsmasq.conf +cat /etc/dnsmasq.d/resolv.conf +cat /etc/resolv.conf +---- + +== Closing words diff --git a/_projects/bash-scriptkitties-overlay.md b/_projects/bash-scriptkitties-overlay.md new file mode 100644 index 0000000..2a0522e --- /dev/null +++ b/_projects/bash-scriptkitties-overlay.md @@ -0,0 +1,7 @@ +--- +title: Scriptkitties Overlay +langs: Bash +license: GPLv2+ +repo: https://c.darenet.org/scriptkitties/overlay +--- + diff --git a/_projects/lua-subbot.md b/_projects/lua-subbot.md new file mode 100644 index 0000000..b073c04 --- /dev/null +++ b/_projects/lua-subbot.md @@ -0,0 +1,6 @@ +--- +title: SubBot +langs: Lua +license: GPLv2 +repo: https://c.darenet.org/tyil/subbot +--- diff --git a/_projects/perl6-app-assixt.md b/_projects/perl6-app-assixt.md new file mode 100644 index 0000000..e8e2868 --- /dev/null +++ b/_projects/perl6-app-assixt.md @@ -0,0 +1,6 @@ +--- +title: App::Assixt +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-app-assixt +--- diff --git a/_projects/perl6-config.md b/_projects/perl6-config.md new file mode 100644 index 0000000..111bb51 --- /dev/null +++ b/_projects/perl6-config.md @@ -0,0 +1,6 @@ +--- +title: Config +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/p6-Config +--- diff --git a/_projects/perl6-dist-helper.md b/_projects/perl6-dist-helper.md new file mode 100644 index 0000000..f84d498 --- /dev/null +++ b/_projects/perl6-dist-helper.md @@ -0,0 +1,6 @@ +--- +title: Dist::Helper +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-dist-helper +--- diff --git a/_projects/perl6-io-path-dirstack.md b/_projects/perl6-io-path-dirstack.md new file mode 100644 index 0000000..e568911 --- /dev/null +++ b/_projects/perl6-io-path-dirstack.md @@ -0,0 +1,6 @@ +--- +title: IO::Path::Dirstack +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-io-path-dirstack +--- diff --git a/_projects/perl6-irc-client-plugin-github.md b/_projects/perl6-irc-client-plugin-github.md new file mode 100644 index 0000000..a8c2d48 --- /dev/null +++ b/_projects/perl6-irc-client-plugin-github.md @@ -0,0 +1,6 @@ +--- +title: IRC::Client::Plugin::Github +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-IRC-Client-Plugin-Github +--- diff --git a/_projects/perl6-irc-client-plugin-ignore.md b/_projects/perl6-irc-client-plugin-ignore.md new file mode 100644 index 0000000..69a95c5 --- /dev/null +++ b/_projects/perl6-irc-client-plugin-ignore.md @@ -0,0 +1,6 @@ +--- +title: IRC::Client::Plugin::Ignore +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-IRC-Client-Plugin-Ignore +--- diff --git a/_projects/perl6-irc-client-plugin-nickserv.md b/_projects/perl6-irc-client-plugin-nickserv.md new file mode 100644 index 0000000..f14fd8d --- /dev/null +++ b/_projects/perl6-irc-client-plugin-nickserv.md @@ -0,0 +1,6 @@ +--- +title: IRC::Client::Plugin::NickServ +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-IRC-Client-Plugin-NickServ +--- diff --git a/_projects/perl6-irc-client-plugin-urltitle.md b/_projects/perl6-irc-client-plugin-urltitle.md new file mode 100644 index 0000000..c428f07 --- /dev/null +++ b/_projects/perl6-irc-client-plugin-urltitle.md @@ -0,0 +1,6 @@ +--- +title: IRC::Client::Plugin::UrlTitle +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/perl6-IRC-Client-Plugin-UrlTitle +--- diff --git a/_projects/perl6-mpd-client.md b/_projects/perl6-mpd-client.md new file mode 100644 index 0000000..a23ab96 --- /dev/null +++ b/_projects/perl6-mpd-client.md @@ -0,0 +1,6 @@ +--- +title: MPD::Client +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/p6-MPD-Client +--- diff --git a/_projects/perl6-musashi.md b/_projects/perl6-musashi.md new file mode 100644 index 0000000..2319f4f --- /dev/null +++ b/_projects/perl6-musashi.md @@ -0,0 +1,6 @@ +--- +title: Musashi +langs: Perl 6 +license: GPLv3 +repo: https://github.com/scriptkitties/musashi +--- diff --git a/_projects/ruby-tachikoma.md b/_projects/ruby-tachikoma.md new file mode 100644 index 0000000..2534939 --- /dev/null +++ b/_projects/ruby-tachikoma.md @@ -0,0 +1,7 @@ +--- +title: Tachikoma +langs: Ruby +license: GPLv3 +repo: https://c.darenet.org/scriptkitties/tachikoma +--- + diff --git a/_slides/perl6-using-app-assixt-to-improve-module-development.md b/_slides/perl6-using-app-assixt-to-improve-module-development.md new file mode 100644 index 0000000..b16c979 --- /dev/null +++ b/_slides/perl6-using-app-assixt-to-improve-module-development.md @@ -0,0 +1,244 @@ +--- +title: "Perl6: Using `App::Assixt` to improve module development" +event: 14th Dutch Perl Workshop +date: 2018-07-07 +--- + +# `App::Assixt` +## Improving module development + +--- + +# About me + +- Patrick Spek (`TYIL`) +- https://www.tyil.nl +- @tyil@mastodon.social + +note: + I have about 10 Perl 6 modules available on CPAN right now. `Config` and + parser modules, `IRC::Client` plugins, `Hash::Merge`, `Dist::Helper` and + `App::Assixt`. + +--- + +# Why? + +- Manually updating JSON is annoying +- Wanted to ease development +- Wanted easier way to distribute + +note: + It's my 2nd project in Perl 6, following `Config`. + +--- + +# How? + +- Uses `Dist::Helper` +- Updates `META6.json` +- Creates skeleton files + +note: + `Dist::Helper` is the base that deals with the actual interaction with the + modules. `App::Assixt` is a CLI frontend with some nice extras to make it + usable. + +--- + +# How do I get it? + +``` +$ zef install App::Assixt +``` + +note: + `App::Assixt` is easily available through `CPAN`, and `zef` is able to + install it cleanly nowadays. + +--- + +# Using it + +``` +$ assixt help +``` + +``` +$ p6man assixt +``` + +note: + - p6man is shipped with `Pod::To::Pager`, still in development! + +--- + +# Creating a new project + +## Manual +``` +$ mkdir my-new-perl6-project +$ cp my-old-project/META6.json my-new-perl6-project/. +$ $EDITOR my-new-perl6-project/META6.json +``` + +## `assixt` +``` +$ assixt new --name=my-new-perl6-project +``` + +note: + - `assixt new` can also be done without arguments, it will ask for a name + then + - additional questions will also be asked to fill out the META6.json + - `assixt` will add gitlab-ci, travis configuration + - default changelog + - gitignore + +--- + +# Adding files + +## Manual +``` +$ mkdir -p lib/App/Local +$ touch lib/App/Local/NewClass.pm6 +$ $EDITOR META6.json +``` + +## `assixt` +``` +$ assixt touch class App::Local::NewClass +``` + +- Classes +- Tests +- Unit modules + +--- + +# Adding a dependency + +## Manual +``` +$ $EDITOR META6.json +$ zef install Config +``` + +## `assixt` +``` +$ assixt depend Config +``` + +note: + `--no-install` skips the step where `zef` tries to install the module. + +--- + +# Bumping the version + +## Manual +``` +$ $EDITOR META6.json +``` + +## `assixt` +``` +$ assixt bump +``` + +note: + - `bump` asks for additional user input to decide whether to bump the patch, + minor or major level. + - In a next release, will also update `=VERSION` in pod, and CHANGELOG + releases. + +--- + +# Create a new dist + +## Manual +``` +$ tar czf My-Dist-0.1.2.tar.gz --exclude-vcs-ignores [--exclude...] . +$ mv !:2 ~/.local/dists/. +``` + +## `assixt` +``` +$ assixt dist +``` + +--- + +# Uploading to CPAN + +## Manual +Through your favourite webbrowser + +## `assixt` +``` +$ assixt upload ~/.local/var/assixt/dists/Dist-Helper-0.19.0.tar.gz +``` + +note: + After starting development and testing of `assixt`, I eventually found `mi6`, + but I stick to `assixt` as it can do much more. + +--- + +# `push` shorthand + +``` +$ assixt push +``` + +- Bump +- Dist +- Upload + +note: + Does a `bump`, `dist` and `upload`, one after another. + +--- + +# Workflow + +``` +$ assixt new Local::App +$ cd perl6-local-app +$ assixt depend Config +$ assixt touch class Local::App::Foo +$ $EDITOR +$ assixt push +``` + +note: + Creates a new module directory, make the module depend on `Config`, create a + class named `Local::App::Foo` and push the module to CPAN. + +--- + +# Future plans + +--- + +## QA check +- Will perform QA checks to improve module quality +- Based on `Release::Checklist` by [Tux] +- Work In Progress on Github + +--- + +## Other ideas +- `meta`: To update misc dist info, such as the authors +- `sync-meta`: To synchronize a `META6.json` from an existing module +- Improve `new`: Also generate a default `README.pod6` + +note: + `sync-meta` is intended to also create a new `META6.json` if none exists + yet. + +--- + +# Questions + diff --git a/css/main.less b/css/main.less new file mode 100644 index 0000000..523cbfc --- /dev/null +++ b/css/main.less @@ -0,0 +1,171 @@ +@bodybgColor: #fefefe; +@bodyTextColor: #454545; + +// Link Colors +@linkColor: #07a; +@linkVisitedColor: #07a; +@linkVisitedInvertedColor: #ac5a82; +// =============== + +@wrongColor: #c0392b; +@shittyBlue: #0000EE; +@shittyViolet: #551A8B; +@motherfuckingColor: #16a085; +@blockQuoteColor: #456; +@openQuoteColor: #666; + +html { + background-color: @bodybgColor; +} + +body { + font-family: Times; + color: @bodyTextColor; + font-size: 16px; + line-height: 1.4; + text-align: justify; + width: 100%; + margin: 0; +} + +small { + font-size: 0.7em; +} + +nav { + padding-bottom: 8px; + border-bottom: double @bodyTextColor; + text-align: center; + font-family: Sans; + + a, a:visited { + margin: 0 0.5em; + font-size: 24px; + text-decoration: none; + color: @bodyTextColor; + } + + .brand-name { + text-align: center; + display: block; + font-weight: bold; + font-size: 32px; + color: @bodyTextColor; + margin-bottom: 8px; + } +} + +a, a:visited { + color: @linkColor; +} + +li p { + margin: 0; +} + +table { + width: 100%; +} + +blockquote{ + color: @blockQuoteColor; + margin-left: 0; + margin-top: 2em; + margin-bottom: 2em; + + span{ + float: left; + margin-left: 1rem; + padding-top: 1rem; + } + + author{ + display: block; + clear: both; + font-size: 0.6em; + margin-left: 2.4rem; + font-style: oblique; + + &:before{ + content: "- "; + margin-right: 1em; + } + } + + &::before{ + font-family: "Times New Roman", Times, Arial; + color: @openQuoteColor; + content: open-quote; + font-size: 2.2em; + font-weight: 600; + float: left; + margin-top: 0em; + margin-right: 0.2rem; + width: 1.2rem; + } + + &::after{ + content: ""; + display: block; + clear: both; + } +} + +pre.pygments { + border: double @openQuoteColor; + padding: 8px; +} + +code { + background-color: #eee; + padding: 2px; +} + +div.container { + max-width: 900px; + margin: 0 auto 0.5em auto; + padding-top: 1em; +} + +span.citneed{ + vertical-align: top; + font-size: 0.7em; + padding-left: 0.3em; +} + +p.text-center { + text-align: center; +} + +@media screen and (max-width: 500px) { + body{ + text-align: left; + } + + div.fancyPositioning{ + div.picture-left{ + float: none; + width: inherit; + } + + div.tleft{ + float: none; + width: inherit; + } + } + + blockquote{ + span{ + width: 80%; + } + author{ + padding-top: 1em; + width: 80%; + margin-left: 15%; + &::before{ + content: ""; + margin-right: inherit; + } + } + } +} diff --git a/css/pygments.scss b/css/pygments.scss new file mode 100644 index 0000000..98fbf5a --- /dev/null +++ b/css/pygments.scss @@ -0,0 +1,71 @@ +--- +--- +.listingblock .pygments .hll { background-color: #ffffcc } +.listingblock .pygments, .listingblock .pygments code { background: #f8f8f8; } +.listingblock .pygments .tok-c { color: #008800; font-style: italic } /* Comment */ +.listingblock .pygments .tok-err { border: 1px solid #FF0000 } /* Error */ +.listingblock .pygments .tok-k { color: #AA22FF; font-weight: bold } /* Keyword */ +.listingblock .pygments .tok-o { color: #666666 } /* Operator */ +.listingblock .pygments .tok-ch { color: #008800; font-style: italic } /* Comment.Hashbang */ +.listingblock .pygments .tok-cm { color: #008800; font-style: italic } /* Comment.Multiline */ +.listingblock .pygments .tok-cp { color: #008800 } /* Comment.Preproc */ +.listingblock .pygments .tok-cpf { color: #008800; font-style: italic } /* Comment.PreprocFile */ +.listingblock .pygments .tok-c1 { color: #008800; font-style: italic } /* Comment.Single */ +.listingblock .pygments .tok-cs { color: #008800; font-weight: bold } /* Comment.Special */ +.listingblock .pygments .tok-gd { color: #A00000 } /* Generic.Deleted */ +.listingblock .pygments .tok-ge { font-style: italic } /* Generic.Emph */ +.listingblock .pygments .tok-gr { color: #FF0000 } /* Generic.Error */ +.listingblock .pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.listingblock .pygments .tok-gi { color: #00A000 } /* Generic.Inserted */ +.listingblock .pygments .tok-go { color: #888888 } /* Generic.Output */ +.listingblock .pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.listingblock .pygments .tok-gs { font-weight: bold } /* Generic.Strong */ +.listingblock .pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.listingblock .pygments .tok-gt { color: #0044DD } /* Generic.Traceback */ +.listingblock .pygments .tok-kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ +.listingblock .pygments .tok-kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ +.listingblock .pygments .tok-kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */ +.listingblock .pygments .tok-kp { color: #AA22FF } /* Keyword.Pseudo */ +.listingblock .pygments .tok-kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ +.listingblock .pygments .tok-kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ +.listingblock .pygments .tok-m { color: #666666 } /* Literal.Number */ +.listingblock .pygments .tok-s { color: #BB4444 } /* Literal.String */ +.listingblock .pygments .tok-na { color: #BB4444 } /* Name.Attribute */ +.listingblock .pygments .tok-nb { color: #AA22FF } /* Name.Builtin */ +.listingblock .pygments .tok-nc { color: #0000FF } /* Name.Class */ +.listingblock .pygments .tok-no { color: #880000 } /* Name.Constant */ +.listingblock .pygments .tok-nd { color: #AA22FF } /* Name.Decorator */ +.listingblock .pygments .tok-ni { color: #999999; font-weight: bold } /* Name.Entity */ +.listingblock .pygments .tok-ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.listingblock .pygments .tok-nf { color: #00A000 } /* Name.Function */ +.listingblock .pygments .tok-nl { color: #A0A000 } /* Name.Label */ +.listingblock .pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.listingblock .pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */ +.listingblock .pygments .tok-nv { color: #B8860B } /* Name.Variable */ +.listingblock .pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.listingblock .pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */ +.listingblock .pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */ +.listingblock .pygments .tok-mf { color: #666666 } /* Literal.Number.Float */ +.listingblock .pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */ +.listingblock .pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */ +.listingblock .pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */ +.listingblock .pygments .tok-sa { color: #BB4444 } /* Literal.String.Affix */ +.listingblock .pygments .tok-sb { color: #BB4444 } /* Literal.String.Backtick */ +.listingblock .pygments .tok-sc { color: #BB4444 } /* Literal.String.Char */ +.listingblock .pygments .tok-dl { color: #BB4444 } /* Literal.String.Delimiter */ +.listingblock .pygments .tok-sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ +.listingblock .pygments .tok-s2 { color: #BB4444 } /* Literal.String.Double */ +.listingblock .pygments .tok-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.listingblock .pygments .tok-sh { color: #BB4444 } /* Literal.String.Heredoc */ +.listingblock .pygments .tok-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.listingblock .pygments .tok-sx { color: #008000 } /* Literal.String.Other */ +.listingblock .pygments .tok-sr { color: #BB6688 } /* Literal.String.Regex */ +.listingblock .pygments .tok-s1 { color: #BB4444 } /* Literal.String.Single */ +.listingblock .pygments .tok-ss { color: #B8860B } /* Literal.String.Symbol */ +.listingblock .pygments .tok-bp { color: #AA22FF } /* Name.Builtin.Pseudo */ +.listingblock .pygments .tok-fm { color: #00A000 } /* Name.Function.Magic */ +.listingblock .pygments .tok-vc { color: #B8860B } /* Name.Variable.Class */ +.listingblock .pygments .tok-vg { color: #B8860B } /* Name.Variable.Global */ +.listingblock .pygments .tok-vi { color: #B8860B } /* Name.Variable.Instance */ +.listingblock .pygments .tok-vm { color: #B8860B } /* Name.Variable.Magic */ +.listingblock .pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/feed.xml b/feed.xml new file mode 100644 index 0000000..6adf38b --- /dev/null +++ b/feed.xml @@ -0,0 +1,23 @@ +--- +layout: null +--- +{% assign documents = site.documents | where: 'feed', true | sort: 'date' | reverse %} + + + {{ site.title | xml_escape }} + {{ site.description | xml_escape }} + {{ site.url }}{{ site.baseurl }}/ + + {{ site.time | date_to_rfc822 }} + {{ site.time | date_to_rfc822 }} + Jekyll v{{ jekyll.version }}{% for post in documents limit:10 %} + + {{ post.title | xml_escape }} + {{ post.date | date_to_rfc822 }} + {{ post.url | prepend: site.baseurl | prepend: site.url }} + {{ post.url | prepend: site.baseurl | prepend: site.url }}{% for tag in post.tags %} + {{ tag | xml_escape }}{% endfor %}{% for cat in post.categories %} + {{ cat | xml_escape }}{% endfor %} + {% endfor %} + + diff --git a/img/cc-by-sa.png b/img/cc-by-sa.png new file mode 100644 index 0000000..5d64b4a Binary files /dev/null and b/img/cc-by-sa.png differ diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..05ea17f --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +--- +--- +Sitemap: {{ site.url }}/sitemap.xml -- cgit v1.1