site_vineetk

Source for vineetk.net website
Log | Files | Refs | LICENSE

commit c58adc06f9b7cfbe818fb7fd3a68f5b66960a620
parent b35228ff7370f8d9ef2b45bd09cfb974acf1254d
Author: Vineet Kumar <git@vineetk.net>
Date:   Tue,  5 May 2026 11:43:52 -0400

switched to haunt from hugo

Diffstat:
ACOPYING | 2++
Darchetypes/default.md | 5-----
Dassets/main.scss | 248-------------------------------------------------------------------------------
Dcontent/_index.html | 3---
Dcontent/blog/kobo_clara-custom-distro.md | 265-------------------------------------------------------------------------------
Dcontent/blog/kobo_clara-nickel.md | 245-------------------------------------------------------------------------------
Dcontent/blog/kobo_clara-plato.md | 129-------------------------------------------------------------------------------
Dcontent/blog/st-bitmap-font-fix.md | 37-------------------------------------
Dcontent/blog/tmpfilehost.md | 73-------------------------------------------------------------------------
Dcontent/blog/vfio-win10.md | 318-------------------------------------------------------------------------------
Ahaunt.scm | 25+++++++++++++++++++++++++
Aimages/bctf23_electronical-mountain_aes.png | 0
Aimages/bctf23_electronical-tux_aes.png | 0
Aimages/crewctf24_sniff/breadboard.jpg | 0
Aimages/crewctf24_sniff/converted_eink_image.png | 0
Aimages/crewctf24_sniff/device.jpg | 0
Aimages/crewctf24_sniff/digikey_datasheet.png | 0
Aimages/crewctf24_sniff/discord1.png | 0
Aimages/crewctf24_sniff/discord2.png | 0
Aimages/crewctf24_sniff/display1.jpg | 0
Aimages/crewctf24_sniff/display2.jpg | 0
Aimages/crewctf24_sniff/everything.jpg | 0
Aimages/crewctf24_sniff/failed_flag.png | 0
Aimages/crewctf24_sniff/flag1.png | 0
Aimages/crewctf24_sniff/flag2.png | 0
Aimages/crewctf24_sniff/logic1.jpg | 0
Aimages/crewctf24_sniff/logic2.jpg | 0
Aimages/crewctf24_sniff/logic2_i2c_1.png | 0
Aimages/crewctf24_sniff/logic2_i2c_2.png | 0
Aimages/crewctf24_sniff/logic2_main.png | 0
Aimages/crewctf24_sniff/logic2_spi.png | 0
Aimages/crewctf24_sniff/logic2_spi_update_times.png | 0
Aimages/crewctf24_sniff/pi1.jpg | 0
Aimages/crewctf24_sniff/pi2.jpg | 0
Aimages/crewctf24_sniff/rpi_pinout.png | 0
Aimages/deadface23-shattered_dreams-forum.png | 0
Dlayouts/blog/rss.xml | 39---------------------------------------
Dlayouts/blog/section.html | 10----------
Dlayouts/partials/foot.html | 4----
Dlayouts/partials/head.html | 14--------------
Aposts/bctf23_electronical.md | 301+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/crewctf24_sniff.md | 369+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/csaw23_rebug1.md | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/deadface23_hostbusters3.md | 37+++++++++++++++++++++++++++++++++++++
Aposts/deadface23_shattered-dreams.md | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/kobo_clara-custom-distro.md | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/kobo_clara-nickel.md | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/kobo_clara-plato.md | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/st-bitmap-font-fix.md | 35+++++++++++++++++++++++++++++++++++
Aposts/tmpfilehost.md | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/vfio-win10.md | 316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aposts/workflow_9years.md | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astatic/agpl-3.0.txt | 661+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dstatic/bsd_license.txt | 24------------------------
Dstatic/cc-by-4.0.txt | 395-------------------------------------------------------------------------------
Astatic/cc-by-nc-sa-4.0.txt | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astatic/main.css | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atheme.scm | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dupdate.sh | 4----
59 files changed, 3678 insertions(+), 1813 deletions(-)

diff --git a/COPYING b/COPYING @@ -0,0 +1 @@ +static/agpl-3.0.txt +\ No newline at end of file diff --git a/archetypes/default.md b/archetypes/default.md @@ -1,5 +0,0 @@ -+++ -title = '{{ replace .File.ContentBaseName "-" " " | title }}' -date = {{ .Date }} -draft = true -+++ diff --git a/assets/main.scss b/assets/main.scss @@ -1,248 +0,0 @@ -$background: #0e0c06; -$foreground: #d4b782; -$black: #1b1918; -$brblack: #544b44; -$red: #d42215; -$green: #358c15; -$yellow: #9a6200; -$blue: #00458d; -$magenta: #773dbf; -$cyan: #008a7b; -$white: #cfb688; - -html { - font-family: sans-serif; - color: $foreground; - background-color: $background; -} - -body { - max-width: 920px; - margin: 0 auto; - padding: 1rem; - font-family: monospace; -} - -h1 { - margin-top: 0; - font-size: 1.5rem; - - small { - display: block; - font-size: 1rem; - } -} - -a { - color: $yellow; - text-decoration: none; -} - -a:hover { - color: $yellow; - text-decoration: underline; -} - -a:visited { - color: $green; -} - -.index { - display: flex; - flex-direction: row; - - .article-list { - flex-grow: 1; - margin: auto; - max-width: 600px; - - .article { - margin-bottom: 1rem; - } - - .date { - display: block; - color: $brblack; - } - } - - aside { - width: 40%; - - img { - display: block; - margin: 0 auto 1rem; - border-radius: 5px; - } - - dt { - font-size: 0.9rem; - } - - dd { - margin-left: 0; - - &:not(:last-child) { - margin-bottom: 0.5rem; - } - } - } - - @media(max-width: 640px) { - aside { - display: none; - } - } -} - -article { - margin: 0 auto; - max-width: 720px; - line-height: 1.3; - - img, video, iframe { - // !important for asciinema frames - display: block !important; - margin: 0 auto !important; - max-width: 90%; - - @media(max-width: 640px) { - max-width: calc(100% - 2rem); - } - } - - .comment { - margin: 2rem auto 0; - max-width: 80%; - color: #333; - } -} - -.footnotes { - font-size: 0.85rem; -} - -footer { - margin-top: 2rem; - text-align: center; - font-size: 0.8rem; - color: #333; -} - -.float-img { - float: right; - display: inline; - padding-left: 1rem; - - @media(max-width: 640px) { - display: block; - float: none; - padding-left: inherit; - } -} - -pre { - background-color: $black; - padding: 0.25rem 1rem; - margin: 0 -1rem; - max-width: 100%; - overflow-x: auto; - - .cp { - color: #800; - } - - .k { - color: #008; - } - - .kt, .kd, .kc { - color: #44F; - } - - .s { - color: #484; - font-style: italic; - } - - .cm, .c1 { - color: #333; - font-style: italic; - } - - .gi { - color: $green; - } - - .gd { - color: $red; - } - - .gu { - color: $blue; - } -} - -summary { - cursor: pointer; - background-color: $black; - padding: 0.25rem 1rem; - margin: 0 -1rem; -} - -details[open] { - border-bottom: 1rem solid $black; - margin: 0 -1rem 1rem; - padding: 0 1rem; -} - -.text-center { - text-align: center; -} - -blockquote { - border-left: 5px solid #bbb; - background-color: $black; - padding: 0 1rem; - margin-left: calc(-1rem - 5px); - margin-right: -1rem; - - blockquote { - margin-right: 0; - margin-left: 0; - } -} - -dl { - display: grid; - grid-template-columns: auto 1fr; - grid-gap: 0.2rem 1rem; - - dt { - font-weight: bold; - grid-column-start: 1; - } - - dd { - grid-column-start: 2; - margin: 0; - } -} - -.alert { - padding: 0.5rem; - border: 1px solid transparent; - margin-bottom: 1rem; - - &.alert-danger { - background: #f8d7da; - color: #721c24; - border-color: #f5c6cb; - } - - &.alert-info { - background: #d1ecf1; - color: #0c5460; - border-color: #bee5eb; - } -} diff --git a/content/_index.html b/content/_index.html @@ -1,3 +0,0 @@ ---- -title: Vineet's site ---- diff --git a/content/blog/kobo_clara-custom-distro.md b/content/blog/kobo_clara-custom-distro.md @@ -1,265 +0,0 @@ -+++ -title = "Kobo Clara HD Custom Linux Distro/RootFS" -date = 2021-07-22 -draft = false -+++ - -These are just some notes I made when creating my own mini-distro after -wanting something more custom than just using buildroot or making the -official firmware more slim. For people other than me, I suggest -looking through (C)LFS or running postmarketOS instead once this -reader's pull request[1] gets integrated into upstream. - -Two things that'll greatly help with this is having serial terminal -access with the four uart pins near the top right in the back of the -reader, near the uSD card slot (I don't connect the 5V pin as my reader -doesn't really turn on anything other than the power LED). I suggest -maybe soldering female pin headers to there to make your life easier -(you can later cut out a hole in the back cover or desolder the headers -once you're done). Other than that, I suggest installing QEMU with ARM -userspace to test programs that you have built or running them on a -separate ARM device like a Raspberry Pi. - -## Prelude -Ever since I learnt that the official firmware for the Clara was just -using a modified Linux kernel with busybox as coreutils and many other -libraries, I just knew that I had to minimize it. I also saw that it -was using glibc for it's libc, which I really dislike as statically -linking C programs against it was a pain in my experience, compared to -something like musl and uclibc. It's also much larger than them and I -don't use any of glibc extensions so it seemed like a waste of space to -me. - -Initially when I replaced Nickel with Plato, I was able to shave about -100 MiB after I removed /usr/local (which contains Nickel, Qt and a few -other things), from 189 MiB to 74 MiB, but I still wanted to make it -smaller. - -Using buildroot, I was able to get it under 2 MiB (!!) which was a -little less than half the size of an uncompressed armhf Alpine Linux -minirootfs (4.9M for 3.14). With Busybox, it was pretty much working -out of the box, with serial terminal access! But waiting around 15 -minutes for the toolchain to build each time I wanted to change -something in the rootfs took way too long, although it could've been -minimized if I used ccache with a fairly large cache size. I still -found that it compiled and installed a lot of things I wouldn't be -using (particularly in /usr) even after disabling almost all of the -third-party packages. - -I've uploaded the config file and the resulting rootfs for -buildroot 2021.05. The root password by default is changeme. -EDIT 2022-10-21: gone, build it yourself - -Of course the rootfs I got from buildroot nor me making the official -firmware smaller is the point of this article, and the actual point is -making one yourself! (or rather what I did to make my own) - -## Cross-toolchain -For now as of July 22, 2021, I'm using my distro (Void Linux)'s -packaged cross toolchain for armhf musl, but eventually I would be -using my own. - -I'm not compiling off of the device itself as it would be somewhat slow -for bigger programs, which is currently primarily the Linux kernel, -U-Boot, and the toolchain itself, considering that the ereader's CPU -(Freescale i.MX 6SLL) is a single core running up to 1 GHz. Including -the development tools and headers would also take up more space on the -device itself, and since the terminal can currently only be accessed -through it's serial/uart pins, I don't think it's ideal. - -TODO: include steps to create own toolchain (probably based off of gcc -4.7.3 as that doesn't require c++) - -## Building the rootfs -Assuming you made a new filesystem on your rootfs's partition, it'll -likely be empty with no directories you'd expect to find on a regular -distro. So you'll just have to make them. -cd /path/to/rootfs -mkdir bin dev etc proc sbin - -Your binaries would usually go in /bin, the uSD card, ttymxc0, and -other devices would go in /dev, felker init's default program/script to -execute is usually in /etc/rc, /proc is optional but I have it mounted -to see what is currently mounted through /proc/mounts (or mount(1) -without any arguments) as well as to see my disk usage through df(1). -/sbin is there to place the init in as /sbin/init is the default init -path the kernel looks at. - -## toybox -Now on to the main part of the distro, the userspace. I intend to keep -it fairly minimal so I've chosen to use toybox along with a slightly -modified version of felker (musl dev)'s init[2], as well as dash[3] as -the main shell since toybox doesn't include one as of 0.8.5 (though -it'll probably be there by 1.0). I'll also be statically linking all -the programs that'll be used so I wouldn't have to worry about shared -libraries not being included/copied over, and also including LTO for -slightly faster binaries. Originally, I tried going with sinit, sbase, -and ubase but I was having trouble getting serial terminal access with -getty to /dev/ttymxc0 (the default serial tty, at least with the -vendor kernel). I didn't have this problem with busybox's and toybox's -getty however. My config for toybox was also about 81K smaller than my -trimmed sbase-box and ubase-box (352K compared to 267K+166K) where I -removed programs that I won't use from ${BIN} in their respective -Makefiles. -EDIT 2022-10-21: also gone - -First I suggest exporting some environment variables to set the -toolchain used as well as enabling static linking and LTO. - - export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc - export CC="${CROSS_COMPILE}gcc" - export LDFLAGS="--static" - export CFLAGS="-flto -static" - export ARCH=arm # for compiling the linux kernel - -To compile toybox, get the source from -https://landley.net/toybox/downloads/ (or clone the upstream repo). -Then run make menuconfig (optionally with make defconfig before it) and -change it as you see fit. Personally, I disabled most of the programs I -wouldn't use and kept only the ones that'll help with fixing a problem. -Finally, make sure to run make. - - make defconfig - make menuconfig - make - -To move it to your rootfs and set it's symlinks, you could probably run -make install after setting PREFIX to your rootfs's /bin directory, but -I did it manually. - - # automatic (didn't test, check README) - make PREFIX=/path/to/rootfs/bin/ install - - # (semi?) manual - cp toybox /path/to/rootfs/bin - - # add symlinks if doing manual and you want them - cd /path/to/rootfs/bin - for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done - -## dash -Also as of toybox 0.8.5, a shell still isn't included (probably would -be included by 1.0 according to scripts/install.sh as well as a few -other programs like gzip), so a separate shell would need to be built. -Any can be used but dash would be shown as an example as I was able to -get a static binary without too much trouble. - -First obtain the source[3] and cd into its -untarred directory. Assuming your CC and CFLAGS are set, you can run -these steps: - - autoreconf -fiv - ./configure --host=$CROSS_COMPILE --with-libedit - make - ${CROSS_COMPILE}strip src/dash - -As this is going to be used as the main shell, I've decided to just -copy it to /bin/sh in the rootfs directory, though copying it there but -as /bin/dash and /bin/sh being symlinked to dash is also an option. - - cp src/dash /path/to/rootfs/bin/sh - # or - cp src/dash /path/to/rootfs/bin - cd /path/to/rootfs/bin - ln -s dash sh - -## felker's init -The init is just a single file that you can get from felker's site[2] -or the gist on github[7]. I haven't had a good experience with the -default startup program (/etc/rc) as a shell script with execve() run -on it so I'd change it to execvp() and remove the third (specifies -environment). To compile and install the init, all you need to do is -run: - - $CC $CFLAGS -o init init.c - cp init /path/to/rootfs/sbin - -Instead of /etc/rc being a shell script, you can also make a C program -that does whatever you think is needed for a proper startup. I'll still -use a shell script though which is linked here. -EDIT 2022-10-21: you get the idea, it's gone. - -## /etc/passwd -Copying the rootfs's contents to your device's/uSD card's root -partition and then turning the device on should now work with a login -prompt shown in the serial terminal. However, you probably wouldn't be -able to login to any user. So you'll have to create a file at -/path/to/rootfs/etc/passwd. For an empty password to root, you can use -this, though I suggest setting a password as soon as you login: - - # in rootfs's /etc/passwd - root::0:0:root:/root:/bin/sh - -With the passwd file created/updated, you should now be able to login -to root after the rootfs is copied to your uSD card. Your rootfs so far -should now be around 550-560K, which is much much smaller than the -original firmware's, though it'll likely be much larger to maybe a few -megabytes once a proper reader software is added. - -## Custom Linux Kernel -WARNING: I haven't actually gotten the kernel to load in u-boot yet. It -just hangs in the "Starting kernel ..." step and the init doesn't get -loaded, so I'm assuming the kernel itself isn't either. If anyone out -there has gotten a custom kernel working in the Kobo Clara HD, please -send me an email or message on xmpp. - -UPDATE Jul 28, 2021: Gave up on it as I just couldn't get any kernels I -built (both vendor and akemnade's mainline) to boot. But neither did -postmarketOS boot beyond the initial initramfs messages without the log -file being created. So I'll revisit this for later. - -EDIT 2022-10-21: I have gotten this working, but have been unable to -get Plato build for musl, so I will have to either continue fighting -with the crab or create my own with fbink, as that still works. -Separate article on this later. - -My next big step is compiling my own kernel for the Clara HD. With the -default configuration built for the vendor kernel, it appears to be -about 3M, so my goal is to build a kernel that is smaller than that -while retaining only the functionality that I need. I'm also not going -to include networking support as that is unneeded for my purposes, but -I suggest just keeping it if you're unsure. The wifi driver for the -Kobo Clara HD is available as an out-of-tree driver[8]. - -You should first obtain the kernel source, with two main options, the -vendor kernel[9] and the mainline kernel (with akemnade's -patches)[10]. For the latter, you need to clone the repo and switch to -the latest kobo/drm-merged branch (kobo/merged-5.13 as of July 25, -2021). - -After you've got them and assuming the CROSS_COMPILE and ARCH -environment variables are set, you'd want to configure the kernel. - -I had a hard time compiling the vendor kernel with many things -disabled, so I've kept my config somewhat similar to the default -config. The config I used is available here (EDIT: dead). - - make menuconfig - make zImage - -Assuming it compiles properly and arch/arm/boot/zImage exists, all -that's needed to is to write it to your uSD card at the 1M offset. -dd if=/path/to/kernel/zImage of=/path/to/uSDdev bs=512 seek=2048 - -## Custom U-Boot -I have not done this yet, nor really plan to, but if you do manage to -compile the Kobo's vendored u-boot source, then all you'd have to do to -install it is: - - dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 - -If I remember correctly, this command was included in an older -firmware's startup script/rcS for updating udev, and it should still -work. - -## Links -[1]: https://gitlab.com/postmarketOS/pmaports/-/merge_requests/2334 -[2]: https://ewontfix.com/14 -[3]: https://git.kernel.org/pub/scm/utils/dash/dash.git -[4]: https://github.com/akemnade/linux/tree/kobo/merged-5.13 -[5]: https://misc.andi.de1.cc/kobo/uboot-env.txt -[6]: https://misc.andi.de1.cc/kobo/ -[7]: https://gist.github.com/rofl0r/6168719/raw/183525e0f0007169a49392b21ceee5b507e3aee8/init.c -[8]: https://github.com/jwrdegoede/rtl8189ES_linux/tree/rtl8189fs -[9]: https://github.com/kobolabs/Kobo-Reader/blob/master/hw/imx6sll-clara/kernel.tar.bz2 -[10]: https://github.com/akemnade/linux/tree/kobo/drm-merged-5.12 diff --git a/content/blog/kobo_clara-nickel.md b/content/blog/kobo_clara-nickel.md @@ -1,245 +0,0 @@ -+++ -title = 'Kobo Clara HD Notes for Nickel' -date = 2021-01-13 -draft = false -layout = "post" -+++ - -My ereader of choice is the Kobo Clara HD and I particularly like it -because my eyes hurt less when reading for long periods of time -compared to when I read on my phone or when I still had my iPad. It -also had much longer battery life and only need to charge it about once -every two weeks when I read for about 4 hours on average daily. - -However, the two notable things I don't like about it is it's included -telemetry, like using Google Analytics by default and keeping a unique -salt - -Spyware/Anti-Features: -- Google Analytics (a lot of actions, if not everything, is sent to -Google) -- Auto-update by default - - I prefer being able to review what the new update provides and - choose not to apply it - - I don't like the new redesign in firmware v4.23.15505 - -I'm also assuming your Kobo reader and it's SD card's device file would -be would located at `/dev/sdf` and be mounted at `/mnt/kobo`. - -If you're going to not be using Nickel and instead be using something -like [Plato](https://github.com/baskerville/plato), there's a newer version of this article available -[here](./kobo-clara-plato.html), but the notes are for ~KSM~ loading Plato directly and not -though k/fmon because I don't want to load Nickel if I'm already using -a different reader. - -## Upgrade/Backup Included SD Card -While the included 8GB microSD card is decent for storing your ebook -library that may not have a lot of images, that would likely not be -enough if you were aiming to read some comics on your ereader as they -can be pretty big (quite a few of mine are over a gigabyte, with some -over. Luckily, you can replace the microSD card with another one. - -Before upgrading, you should backup the SD card to into an image file -so the filesystem would be preserved when putting the contents of the -image on the new SD card. I'm using the command dd but there might be -another program doing the same thing. Even if you're not going to -upgrade, I still suggest to backup the SD card in case something goes -wrong. -```sh -dd if=/dev/sdf of=kobo_sd.img conv=sync -``` - -After this is done, you can plug in your new SD card and reimage -kobo_sd.img onto it. With dd, you can do something like: -```sh -dd if=kobo_sd.img of=/dev/sdf conv=sync -``` - -Checking it's partition table via lsblk or fdisk -l should show three -partitions. If you replaced the SD card with something bigger, than you -should resize the third partition. - -## Bypassing Registration On Setup -When setting up your Kobo, you will be asked to sign into a Kobo -account. There are other options like logging in via Google, Walmart, -and other stores, but I don't like having to login to a device that -would likely not be connected to the public internet. Fortunately, you -can bypass this by choosing that you cannot connect to a Wi-Fi network -and mount your Kobo to your computer. In, `.kobo/KoboReader.sqlite`, you -can run: -```sh -echo "INSERT INTO user(UserID,UserKey) VALUES('1','');" \ - | sqlite3 KoboReader.sqlite -``` - -This way you don't have to install their application just to be able to -use your device. - -Note: Do not try doing this when you still have your SD card mounted -before you setup your device. The device's screen would likely not -update, at least on an early firmware version like v4.7.10733. - -## Blocking Google Analytics and other Telemetry -Just adding 0.0.0.0 analytics.google.com to `/etc/hosts` may be enough to -block most of the telemetry from being sent. However, you can try -intercepting what connections your Kobo is making via mitmproxy set to -transparent mode or using a hosts file that blocks all connections to -Google (but not necessarily to Kobo's servers) like [Baobab's hosts file](https://codeberg.org/baobab/hosts) -[(raw)](https://codeberg.org/baobab/hosts/raw/branch/master/hosts). -EDIT 2022-10-21: Baobab has deleted his account from Codeberg for quite a -while, so these two links are dead. Instead, I now recommend [Steven Black's](https://github.com/StevenBlack/hosts) -instead [(raw)](https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts). - -To put the hosts file without root (which will be detailed in another -section), you can make a directory called etc, put the hosts file in -there, and tar it into a file called KoboRoot.tgz. -```sh -mkdir etc -wget -O etc/hosts https://codeberg.org/baobab/hosts/raw/branch/master/hosts -tar czvf KoboRoot.tgz etc -cp KoboRoot.tgz /mnt/kobo/.kobo/ -``` - -When you move a tar file with that name into your Kobo's .kobo folder, -it's contents gets untarred into it's root at `/` when the device is -turned on again, which is usually done for their updates but can be -used for custom files like this and gaining root access. - -## Gaining Root Access via Telnet -To gain root access, we first need to get the `/etc/inittab` and -`/etc/inetd.conf` which you can get from mounting the SD card's first -partition into your computer (the second partition seems to be like a -backup). You should copy those two files into a folder called etc -somewhere (probably not on the SD card). - -In the `etc/inittab` file, you should add these two lines: -``` -::sysinit:/etc/custominit.sh -::respawn:/usr/sbin/inetd -f /etc/inetd2.conf -``` - -You would want to rename the `etc/inetd.conf` file you copied into -`etc/inetd2.conf` (or whatever the custom inetd.conf's filename is) and -when editing that, you should add: -``` -23 stream tcp nowait root /bin/busybox telnetd -i -``` - -However, if there is already a commented line for root telnet in the -inetd2.conf, you should probably still add the above line and ignore -the commented line as that may or may not work (didn't for me). - -To actually start inetd, you should add these lines somewhere in -`/etc/custominit.sh`: -```sh -mkdir -p /dev/pts -mount -t devpts devpts /dev/pts -/usr/sbin/inetd /etc/inetd2.conf -``` - -After that, you just have to tar the `etc/` folder again and copy it to -your Kobo's onboard/third partition's `.kobo` folder. -```sh -tar czvf KoboRoot.tgz etc -cp KoboRoot.tgz /mnt/kobo/.kobo/ -``` - -Now you could put your SD card back into your Kobo provided that they -are already unmounted and turn your Kobo back on. - -After connecting to the WiFi, simplying telnetting (?) into your Kobo -and logging in as root should give you a root shell. :D -```sh -telnet $KOBO_IP -``` - -By default, root has no password so you should change it with passwd. - -## Getting SSH and SFTP access via Dropbear -I'm using Dropbear instead of OpenSSH because it's better suited for -embedded hardware like the Kobo Clara HD. Obviously we can't copy a -binary compiled for amd64 or whatever architecture your compiling -computer is running so we would have to cross-compile for our ereader. - -Fortunately, we are not required to cross-compile `gcc`/`clang` and friends -as we can simply download the linaro arm toolchain which has the -binaries for gcc and others included. You could get the toolchain -[here](https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/) and you should get the release that matches your host's - -architecture. After untarring the file, you should also set your PATH -variable to the toolchain's `bin/` folder so you don't have to manually -set the CC and CXX variables when building Dropbear. - -```sh -wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -export PATH=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH -``` - -Now you could get the source for Dropbear and cross-compile it. The -source can be found on their [homepage](https://matt.ucc.asn.au/dropbear/dropbear.html) or [github](https://github.com/mkj/dropbear/releases) repo. -```sh -wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2020.81.tar.bz2 -tar xvf dropbear-2020.81.tar.bz2 -cd dropbear-2020.81 -./configure --enable-static --host=arm-linux-gnueabihf -# MULTI=1 combines the binaries like busybox does and is also smaller in size -make MULTI=1 PROGRAMS="dropbear dropbearkey" -``` - -Now you only need to copy the dropbearmulti binary over to your Kobo. -What I've done is running `python3 -m http.server` and downloading the -file onto my Kobo but you could also just copy it onto the microSD -card. -```sh -wget your.computer.ip:8000/dropbearmulti -chmod +x dropbearmulti -mv dropbearmulti /usr/bin -cd /usr/bin -# below are optional but dropbear(key) would be an argument for dropbearmulti -ln -s dropbearmulti dropbear -ln -s dropbearmulti dropbearkey -``` - -Now you only need to generate the host keys. My client key is ed25519 -so I'm not going to generate the others. -```sh -mkdir /etc/dropbear -dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key -dropbear -F -r /etc/dropbear/dropbear_ed25519_key -``` - -Now you could `ssh` into your Kobo and login as `root`. Remember to change -`root`'s password beforehand though if you haven't already! I suggest -copying your public key to your Kobo via `ssh-copy-id` so you don't have -to enter root's password all the time and so password-based logins can -be disabled in dropbear. - -To start it on boot, you could add the following line to -`/etc/inetd2.conf`: -``` -22 stream tcp nowait root /usr/bin/dropbearmulti dropbear -i -r /etc/dropbear/dropbear_ed25519_key -``` - -For some reason, the symlink wasn't resolving for me inetd so I had to -call the multi-binary directly. You could also add the command/args -into `/etc/custominit.sh`. - -## FTP Access -If you don't or can't use sftp or scp for some reason, there's always ftp :D -There's a ftp daemon included in busybox so all we have to do is enable it -in `/etc/inetd2.conf`: -``` -21 stream tcp nowait root /bin/busybox ftpd -w -S / -``` - -This would share the entire filesystem so you may or may not want to -restrict the shared directory to maybe just your ebook directory -(`/mnt/onboard`) and move the files out via `telnet` or `ssh`. -EDIT 2022-10-21: A chroot would also work. - -## References and Other Links -- [Rémy's notes on hacking a Kobo Aura H2O](https://remy.grunblatt.org/kobo-aura-h2o-electronic-reader-hacking.html) -- [Ying's notes on bypassing registration and setting up telnet, ssh, etc.](https://yingtongli.me/blog/2018/07/30/kobo-rego.html) -- [MobileRead forum thread on disabling Google Analytics on the Kobo Touch](https://www.mobileread.com/forums/showthread.php?t=162713) -- [MobileRead wiki on hacking the Kobo Touch](https://wiki.mobileread.com/wiki/Kobo_Touch_Hacking) diff --git a/content/blog/kobo_clara-plato.md b/content/blog/kobo_clara-plato.md @@ -1,129 +0,0 @@ -+++ -title = "Kobo Clara HD Notes for Plato (and KSM)" -date = 2021-03-27 -+++ - -These are my notes for getting Plato on the Kobo Clara HD from scratch -as well as some notes for getting KSM to work, but I now boot directly -into Plato instead of through KSM. - -Previously, I didn't really like using KOReader because it was kind of -slow and was written in Lua. At the time of using Plato, it seemed nice -but it didn't cover thumbnails for books, which while it is a minor -detail, I find books easier to be recognized with a cover thumbnail in -addition to their title. This was added in release 0.9.10 but as an -optional feature which I didn't somehow see until recently when I -retried it. HOWEVER again, I didn't like using k/fmon as I had to still -use Nickel to get back into KOReader/Plato/whatever alternate reader -when I wanted to go away from using Nickel. - -&lt;ignore&gt; -That was when I found out about KSM and how there was a working version -for the Clara HD. KSM is like an alternate bootloader for the Kobo -readers and it apparently doesn't work very well with newer models like -the Clara HD and up, but someone got it to work with those devices. -[KSM 09](https://www.mobileread.com/forums/showthread.php?s=c34e41df391c61810a6b06f991c29168&t=293804) is apparently not maintained anymore and I'm not sure if KSM -10 is being developed or not since I'm pretty sure it's closed source. - -> Development and support for KSM stopped some time ago. Therefore, do -> not use it! - -"That sign can't stop me because I can't read!" - Me imitating D.W. -from the PBS Kids cartoon Arthur on Mar. 26, 2021 when I saw that it -can be used on my Kobo - -The latest firmware version that KSM sort of supports is v4.25.15875 -but it can probably work with a newer version like v4.26+ that would -likely only need a couple changes to /etc/init.d/rcS, if any changes -were needed at all. I'll be using v4.26 for the rest of this -article/guide. -&lt;/ignore&gt; - -Recently, after seeing how my Kobo boots into KSM and Nickel through -the rcS file, I realized that I could've instead just booted directly -into Plato, and plato.sh (the script that runs Plato) has a standalone -option that supports just that! The KSM notes are still going to be -here in case someone still wants to use KSM. - -## Installing Plato (or probably any other reader like KOReader) -This part probably applies to any other reader other than Plato like -KOReader but I haven't personally tested them. All you have to do is -[get the latest release](https://github.com/baskerville/plato/releases/latest) at Plato's repo and unzip it's contents into -a folder called plato in /path/to/kobo/mount/.adds, the latter folder -of which should have already been created by KSM if you are using that. -If you are using KSM, there should be a new option below "start nickel" -called "start plato" when you have rebooted the device. Read below if -you aren't using KSM. - -## Loading Plato on Boot -Since I don't want to load Nickel only to load into another reader like -the recommended options in Plato's forum thread (kfmon, fmon, and -NickelMenu) suggest, I noticed that I could have booted into Plato -directly. The only requirements for doing this having access to the -rootfs, so either through a telnet/ssh session, or having the sd card's -root/first partition mounted to your computer, or just ftp/rsyncing the -files to your Kobo. - -First I suggest making a copy of rcS if you haven't already in case an -update overwrites it. My copy is named custominit.sh. Next you'll want -the Kobo's /etc/inittab to boot with custominit.sh instead of rcS: -/etc/inittab: - -``` -#::sysinit:/etc/init.d/rcS -::sysinit:/etc/custominit.sh -``` - -The rest of the lines don't need to change. Then you should open -custominit.sh in your favourite editor to add the lines at the bottom -but before hindenburg is executed: - -``` -cd /mnt/onboard/.adds/plato # or whereever Plato is -PLATO_STANDALONE=1 ./plato.sh -``` - -You would probably also want to remove the lines where Nickel-specific -programs/scripts are running like nickel, hindenburg, pickel, sickel, -etc. - -Now on subsequent boots, Plato should automatically have been loaded. -Boot times may also be slightly faster! :D - -## Installing KSM 09 (not doing anymore) -First you would want to [download the Clara HD version of KSM 09](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=166556&d=1538176531) and -[the fix for v4.25](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=184756&d=1610745905). Then, you would want to unzip the KoboRoot.tgz -with separate filenames so they don't replace each other and we would -untar those into the same directory. After that, we would cd into the -directory and tar it's contents into a new KoboRoot.tgz and place it in -/path/to/kobo/mount/.kobo/. - -An example of what I did after downloading and unzipping the files are -below: - -``` -mkdir koboroot -tar -xvf KoboRoot-main.tgz -C koboroot -tar -xvf KoboRoot-v4.25-darkmodefix.tgz -C koboroot -cd koboroot -tar -czvf ../KoboRoot.tgz . -cd .. -rm -r koboroot -``` - -After your Kobo untars it and you wait a while, you should be presented -with KSM's main screen :D ksm09's main screen running on the kobo clara -hd - -## Auto-Boot into Plato instead of Nickel via KSM (not doing anymore) -First make sure USB support is enabled in KSM and then mount your Kobo -to your computer. Once mounted, go to -/path/to/kobo/mount/.adds/kbmenu_user/confoptions and edit -ksm_ini_options.txt in your favourite editor. You should see many -options that are listed but the one that we're interested in is -ksmAutoselectoption which may have start_nickel and start_koreader -already and what we want to do is add ksmAutoselectoption=start_plato. -After a quick restart to reload the options file, you should be able to -see the new option in KSM's settings under [general] and add item if it -wasn't already added. Now Plato should auto-boot on subsequent -powerons. diff --git a/content/blog/st-bitmap-font-fix.md b/content/blog/st-bitmap-font-fix.md @@ -1,37 +0,0 @@ -+++ -title = "Fixing bitmap font fallbacks in the st terminal" -date = 2023-11-24 -draft = false -+++ -tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) - -For some context, I have been using xterm for a long while when I'm on OpenBSD -since it is included by default in Xenocara with Terminus as my default font, -and the main reason why I did not use st again was that my bitmap fallback font -for CJK was not loading. Instead, I get an ugly sans-serif scaled font that -looked very out of place in my otherwise clean and crisp bitmap terminal. - -Yes, I did make sure that the font2 patch for st was applied correctly. - -The X11 font string for reference is Fixed: --misc-fixed-medium-r-normal-ja-18-120-100-100-c-180-iso10646-1 - -It also didn't help that fontconfig was unable to find the font either no -matter how much I looked for it with fc-list and fc-match. The weirder thing is -that when I installed GNU Unifont to my fonts directory, fontconfig was able to -find it and st loaded it (I put a printf in the xloadfonts() function in x.c), -but the same old ugly scaled font was still being shown for CJK. The weirderer -thing was that Unifont was rendering just fine when being used as the main font -instead of in font2. - -I thought to myself why this was happening and wasn't able to find out, until I -reread the font loading portion in x.c's xloadsparefonts() function that came -part of the font2 patch. - -It had set the FC_SCALABLE boolean to 1 (true). That explained why the fallback -font rendered fine as the main font and not fallback. Setting that boolean to -0 (false) fixed my fallback font not matching issue, and now I have clean and -crisp looking text that I can read more easily. - -I already disliked fontconfig, freetype, xft, and friends (don't get me started -on pango and harfbuzz), but this incident made me dislike it further. diff --git a/content/blog/tmpfilehost.md b/content/blog/tmpfilehost.md @@ -1,73 +0,0 @@ -+++ -title = "Creating a Temporary File Hoster" -date = 2022-04-27 -draft = false -+++ -For the past couple years, whenever I wanted to upload a file, I would -curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh). - -Since I want to selfhost, I thought i can just use either of what those -three used. Earlier today though, I realized I could just copy the -file(s) I want to upload via rsync/scp to a public directory that gets -served by an httpd or gopherd. - -From what I understand, the previous file hosters had a program running -that read the file that the user uploads to them, does some renaming, -and writes that to a directory that is served. After some time, that -file is deleted. The first part can be handled via rsync/scp like -mentioned previously. For automatic deletion, I recently saw in find's -man page that it can list that haven't been modified via the -mtime -flag, so that can be used with a cron job. - -But while thinking of this idea, I got stumped by how to print back the -url to this file that is uploaded since printing the filename as is -appended to its baseurl, there could be spaces and other invalid -unescaped characters which programs trying to download it may not like. - -I thought I could just create a separate program for this. However, -doing this seemed more complicated than just copying the file to the -server. So, with the help of awk and some StackExchanging, I've been -able to do it. - -`upfile.sh`: -```sh -#!/bin/sh -urlencode() { - awk ' -BEGIN { for (i = 1; i < 256; i++) hex[sprintf("%c", i)] = sprintf("%%%02X", i) } -{ - for (i = 1; i <= length($0); i++) { - c = substr($0, i, 1) - printf("%s", c ~ /^[-._~0-9a-zA-Z]$/ ? c : hex[c]) - } - printf "\n" -} -' -} - -FILE="$1" -SERVER="REPLACEME" -BASEURL="https://u.$SERVER" - -[ -z "$1" ] && exit 1 - -scp "$FILE" "$SERVER":files/ || exit 1 -printf "%s/" "$BASEURL" -basename "$FILE" | urlencode -``` - -Then to purge these files after they become too old (e.g. 3 days), you -can put something like this in a cron job to run daily (replace file -directory): - -``` -0 0 * * * find /path/to/dir/ -mtime +3 -exec rm {} \; -``` - -You can also put this command in /etc/daily.local or /etc/cron/daily, -or whatever file your root crontab's @daily runs (if there is one). - -And that's it! The only difficult part that I experienced was encoding -the name of the file and originally did that in C. However, having a -mixed C and shell program just for file uploading didn't sit right with -me. It seems like whenever you're in doubt, you can rely on awk huh. diff --git a/content/blog/vfio-win10.md b/content/blog/vfio-win10.md @@ -1,318 +0,0 @@ -+++ -title = "VFIO Install Notes" -date = 2020-10-17 -draft = false -+++ -You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge. - -# Prerequisites -## UEFI Options -Enable VT-d and VT-x (or AMD equivalent) - -## Kernel Config -Enable KVM and VFIO -> you can set VFIO as builtin but as a module is more flexible -Also add `"iommu=pt intel_iommu=on"` to your kernel command line (or in CONFIG\_CMDLINE) - -### Current Options -``` -... -CONFIG_IOMMU_IOVA=y -CONFIG_IOMMU_API=y -CONFIG_IOMMU_SUPPORT=y -CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y -# use the respective AMD options if using an AMD CPU -CONFIG_INTEL_IOMMU=y -CONFIG_INTEL_IOMMU_SVM=y -CONFIG_INTEL_IOMMU_DEFAULT_ON=y -CONFIG_INTEL_IOMMU_FLOPPY_WA=y - -CONFIG_KVM_VFIO=y -CONFIG_VFIO_IOMMU_TYPE1=m -CONFIG_VFIO_VIRQFD=m -CONFIG_VFIO=m -CONFIG_VFIO_PCI=m -CONFIG_VFIO_PCI_VGA=y -CONFIG_VFIO_PCI_MMAP=y -CONFIG_VFIO_PCI_INTX=y -CONFIG_VFIO_PCI_IGD=y -CONFIG_VFIO_MDEV=m -CONFIG_VFIO_MDEV_DEVICE=m -... -``` - -## Packages Required -``` -app-emulation/qemu (actual program) -sys-firmware/edk2-ovmf (UEFI firmware for Nvidia GPU) -media-sound/scream (audio) -looking-glass-client (compile from source if no package, or make your own) -``` - -`app-emulation/libvirt` can be used as well for easier configuration and autostart -but I have had problems with it: -- Service not starting properly, workaround is restarting service after it starts (Gentoo) -- Networks and domains not autostarting, workaround is starting them manually (CRUX) - -### Gentoo USE Flags -``` -app-emulation/qemu gtk opengl sdl sdl-image usb # (spice, ssh, vhost-user-fs, virgl, and virtfs are optional I think) -media-libs/libsdl2 X gles opengl # for Looking Glass -``` -note to self (2020-10-17): check how minimal you can make qemu to run vfio - -# IOMMU -Run `dmesg | grep -E 'DMAR'` and see if `DMAR: IOMMU enabled` or something similar is in output - -# QEMU Script -All code blocks in this section go in the qemu script file unless specified otherwise - -## Environment Variables -```sh -IMG=/path/to/windows-image-file -VIRTIO=/path/to/virtio-iso -WINDOWS=/path/to/windows-install-iso -OVMF=/usr/share/edk2-ovmf/OVMF_CODE.fd -RAM=16G -ULIMIT=$(ulimit -l) -ULIMIT_TARGET=$(( $(echo $RAM | tr -d 'G')*1048576+100000 )) - -GPU_VIDEO=01:00.0 -GPU_AUDIO=01:00.1 -VIDEOID="10de 13c0" -AUDIOID="10de 0fbb" -VIDEOBUSID="0000:${GPU_VIDEO}" -AUDIOBUSID="0000:${GPU_AUDIO}" -``` - -## VFIO Detaching and Attaching -```sh -vfio_on() { - # for nvidia card with proprietary drivers - rmmod nvidia_drm - rmmod nvidia_modeset - rmmod nvidia - - # disable bumblebee service or use bbswitch to detach card if using bumblebee - - modprobe vfio-pci - - echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/new_id - echo $VIDEOBUSID > /sys/bus/pci/devices/$VIDEOBUSID/driver/unbind - echo $VIDEOBUSID > /sys/bus/pci/drivers/vfio-pci/bind - echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/remove_id - - echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/new_id - echo $AUDIOBUSID > /sys/bus/pci/devices/$AUDIOBUSID/driver/unbind - echo $AUDIOBUSID > /sys/bus/pci/drivers/vfio-pci/bind - echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/remove_id - - # add rest of gpu devices if they are in the same group (I think 4 devices in 1000 or 2000 series nvidia) -} - -vfio_off() { - rmmod vfio_iommu_type1 - rmmod vfio_pci - rmmod vfio_virqfd - rmmod vfio - - modprobe nvidia -} -``` - -## Networking -```sh -net_on() { - ip tuntap add dev tap0 mode tap group kvm - ip link set dev tap0 up promisc on - ip addr add 0.0.0.0 dev tap0 - - ip link add br0 type bridge - ip link set br0 up - ip link set tap0 master br0 - echo 0 > /sys/class/net/br0/bridge/stp_state - ip addr add 192.168.123.1/24 dev br0 - - sysctl net.ipv4.conf.tap0.proxy_arp=1 > /dev/null - sysctl net.ipv4.conf.enp0s31f6.proxy_arp=1 > /dev/null - sysctl net.ipv4.ip_forward=1 > /dev/null - - iptables -t nat -A POSTROUTING -o enp0s31f6 -j MASQUERADE > /dev/null - iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null - iptables -A FORWARD -i br0 -o enp0s31f6 -j ACCEPT > /dev/null -} - -net_off() { - sysctl net.ipv4.conf.tap0.proxy_arp=0 > /dev/null - sysctl net.ipv4.conf.enp0s31f6.proxy_arp=0 > /dev/null - sysctl net.ipv4.ip_forward=0 > /dev/null - - ip link set dev br0 down - ip link del br0 - - ip link set dev tap0 down - ip tuntap del mode tap name tap0 -} -``` - -Also add this to /etc/conf.d/net if using Gentoo ([source](https://wiki.gentoo.org/wiki/QEMU/Options#Network_bridge)) -> replace `enp0s31f6` with the host/master interface -```sh -... -tuntap_tap0="tap" -config_tap0="null" -bridge_br0="enp0s31f6 tap0" - -config_br0="192.168.123.2 netmask 255.255.255.0" -routes_br0="default via 192.168.123.1" -bridge_forward_delay_br0=0 -bridge_hello_time_br0=10 - -depend_br0() { - need net.enp0s31f6 - need net.tap0 -} -... -``` - -## Hugepages -```sh -hugepages_on() { - PAGES=$(( $(echo $RAM | tr -d 'G') * 1048576 / 2048)) - mkdir -p /dev/hugepages - mount -t hugetlbfs hugetlbfs /dev/hugepages - echo $PAGES > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages -} - -hugepages_off() { - echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages - umount /dev/hugepages -} -``` - -## QEMU Command -### Before installing guest OS (Windows 10 used as example) -```sh -ulimit -l $ULIMIT_TARGET - -qemu-system-x86_64 \ - -name 'vfio-vm' \ - -vga qxl \ - -nodefaults -enable-kvm -machine q35 \ - -m $RAM -mem-path /dev/hugepages \ - -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ - -smp 8,sockets=1,cores=4,threads=2 \ - -rtc clock=host,base=localtime \ - -boot menu=on -boot d \ - -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ - -drive if=pflash,format=raw,readonly,file=$OVMF \ - -drive file="$VIRTIO",id=cd1,media=cdrom \ - -drive file="$WINDOWS",id=cd2,media=cdrom \ - -device virtio-scsi-pci,id=scsi0 \ - -device scsi-hd,bus=scsi0.0,drive=rootfs \ - -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none - -ulimit -l $ULIMIT -``` -### After installing guest OS -```sh -ulimit -l $ULIMIT_TARGET - -qemu-system-x86_64 \ - -name 'vfio-vm' \ - -vga none -nographic \ - -nodefaults -enable-kvm -machine q35 \ - -m $RAM -mem-path /dev/hugepages \ - -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ - -smp 8,sockets=1,cores=4,threads=2 \ - -rtc clock=host,base=localtime \ - -boot menu=on -boot c \ - -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ - -device vfio-pci,host=$GPU_VIDEO,multifunction=on,x-vga=on \ - -device vfio-pci,host=$GPU_AUDIO \ - -device ivshmem-plain,memdev=ivshmem,bus=pcie.0 \ - -object memory-backend-file,id=ivshmem,share=on,mem-path=/dev/shm/looking-glass,size=32M \ - -device virtio-keyboard-pci \ - -device virtio-mouse-pci \ - -object input-linux,id=kbd0,evdev=/dev/input/by-id/usb-Corsair_Corsair_K70R_Gaming_Keyboard-if02-event-kbd,grab_all=on,repeat=on \ - -object input-linux,id=mouse0,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-event-mouse \ - -object input-linux,id=mouse1,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-if01-event-kbd,grab_all=on,repeat=on \ - -drive if=pflash,format=raw,readonly,file=$OVMF \ - -drive file="$VIRTIO",id=cd1,media=cdrom \ - -device virtio-scsi-pci,id=scsi0 \ - -device scsi-hd,bus=scsi0.0,drive=rootfs \ - -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none - -ulimit -l $ULIMIT -``` - -# Extra -## Adding USB Devices -Get vendor and product id from `lsusb` and add them to your QEMU command arguments: -```sh - -device qemu-xhci,id=xhci0 -device usb-host,bus=xhci0.0,vendorid=0x<yourvendorid>,productid=0x<yourproductid> -``` -Example for my USB bluetooth receiver: -``` -$ lsusb -... -Bus 001 Device 004: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth -... -``` -My vendorid is `0x0b05` and productid is `0x17cb`, so in QEMU it would be: -```sh - -device qemu-xhci,id=<usb-bus-id> -device usb-host,bus=<usb-bus-id>.0,vendorid=0x0b05,productid=0x17cb -``` - -## Set CPU Affinity -While libvirt makes this more simple, it appears we need a script/function to do it in bare QEMU -Borrowed from [here](https://null-src.com/posts/qemu-optimization/post.php#taskset) -> note: uses bash-isms so that's why I put it in a separate file -```bash -#!/bin/bash -THREAD_LIST="0,4,1,5,2,6,3,7" -NAME="vfio-vm" - -sleep 20 && -HOST_THREAD=0 -# for each vCPU thread PID -for PID in $(pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | awk -F',' '{print $2}' | awk '{print $1}') | grep CPU | pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | cut -d',' -f2 | cut -d' ' -f1) | grep CPU | sort | awk -F',' '{print $2}') -do - let HOST_THREAD+=1 - # set each vCPU thread PID to next host CPU thread in THREAD_LIST - echo "taskset -pc $(echo $THREAD_LIST | cut -d',' -f$HOST_THREAD) $PID" | sh -done -``` - -## Additional Disk -You can add another disk by simply copying the arguments for adding the rootfs and slightly modifying -Example for a qcow2 image: -``` - -device virtio-scsi-pci,id=<scsi-id> \ - -device scsi-hd,bus=<scsi-id>.0,drive=<drive-id> \ - -drive file=<location>,id=<drive-id>,index=0,format=qcow2,media=disk,if=none -``` - -## No Drives During Installation -Make sure virtio driver is loaded: -- Click Load Driver -- Choose virtio-cd disc > amd64 > w10 and press enter -- Load Red Hat Virtio SCSI driver - -## Looking Glass Not Starting -Make sure no virtual display like QXL is loaded too (`-nographic -vga none` in QEMU) - -## JACK Support -To use JACK instead of Scream, you can use these QEMU arguments -```sh --audiodev jack,id=snd0,in.client-name=default,out.client-name=default,in.start-server=off,out.start-server=off,in.exact-name=on,out.exact-name=on,in.connect-ports=system,out.connect-ports=system,in.frequency=48000,out.frequency=48000,timer-period=2048,out.buffer-length=5120 \ --device ich9-intel-hda \ --device hda-output,audiodev=snd0 \ -``` -You might need to change the timer-period and buffer-length if experiencing crackling. -Also you might have to change the controller (ich9-intel-hda) and codec (hda-output) to something else. - -To list controller and codecs, run: -```sh -qemu-system-x86_64 -device help | grep hda -``` diff --git a/haunt.scm b/haunt.scm @@ -0,0 +1,25 @@ +(use-modules (haunt asset) + (haunt builder blog) + (haunt builder atom) + (haunt builder assets) + (haunt reader commonmark) + (haunt publisher rsync) + (haunt post) + (haunt site) + (theme)) + +(site #:title "Vineet's site" + #:domain "vineetk.net" + #:default-metadata + '((author . "Vineet K") + (email . "me@vineetk.net")) + #:readers (list commonmark-reader) + #:builders (list (blog #:theme vin-theme + #:collections + `(("Posts" "index.html" ,posts/reverse-chronological))) + (atom-feed) + (static-directory "images") + (static-directory "static")) + #:publishers (list (rsync-publisher #:destination "/var/www/vineetk_html/" + #:user "vin" + #:host "saklas"))) diff --git a/images/bctf23_electronical-mountain_aes.png b/images/bctf23_electronical-mountain_aes.png Binary files differ. diff --git a/images/bctf23_electronical-tux_aes.png b/images/bctf23_electronical-tux_aes.png Binary files differ. diff --git a/images/crewctf24_sniff/breadboard.jpg b/images/crewctf24_sniff/breadboard.jpg Binary files differ. diff --git a/images/crewctf24_sniff/converted_eink_image.png b/images/crewctf24_sniff/converted_eink_image.png Binary files differ. diff --git a/images/crewctf24_sniff/device.jpg b/images/crewctf24_sniff/device.jpg Binary files differ. diff --git a/images/crewctf24_sniff/digikey_datasheet.png b/images/crewctf24_sniff/digikey_datasheet.png Binary files differ. diff --git a/images/crewctf24_sniff/discord1.png b/images/crewctf24_sniff/discord1.png Binary files differ. diff --git a/images/crewctf24_sniff/discord2.png b/images/crewctf24_sniff/discord2.png Binary files differ. diff --git a/images/crewctf24_sniff/display1.jpg b/images/crewctf24_sniff/display1.jpg Binary files differ. diff --git a/images/crewctf24_sniff/display2.jpg b/images/crewctf24_sniff/display2.jpg Binary files differ. diff --git a/images/crewctf24_sniff/everything.jpg b/images/crewctf24_sniff/everything.jpg Binary files differ. diff --git a/images/crewctf24_sniff/failed_flag.png b/images/crewctf24_sniff/failed_flag.png Binary files differ. diff --git a/images/crewctf24_sniff/flag1.png b/images/crewctf24_sniff/flag1.png Binary files differ. diff --git a/images/crewctf24_sniff/flag2.png b/images/crewctf24_sniff/flag2.png Binary files differ. diff --git a/images/crewctf24_sniff/logic1.jpg b/images/crewctf24_sniff/logic1.jpg Binary files differ. diff --git a/images/crewctf24_sniff/logic2.jpg b/images/crewctf24_sniff/logic2.jpg Binary files differ. diff --git a/images/crewctf24_sniff/logic2_i2c_1.png b/images/crewctf24_sniff/logic2_i2c_1.png Binary files differ. diff --git a/images/crewctf24_sniff/logic2_i2c_2.png b/images/crewctf24_sniff/logic2_i2c_2.png Binary files differ. diff --git a/images/crewctf24_sniff/logic2_main.png b/images/crewctf24_sniff/logic2_main.png Binary files differ. diff --git a/images/crewctf24_sniff/logic2_spi.png b/images/crewctf24_sniff/logic2_spi.png Binary files differ. diff --git a/images/crewctf24_sniff/logic2_spi_update_times.png b/images/crewctf24_sniff/logic2_spi_update_times.png Binary files differ. diff --git a/images/crewctf24_sniff/pi1.jpg b/images/crewctf24_sniff/pi1.jpg Binary files differ. diff --git a/images/crewctf24_sniff/pi2.jpg b/images/crewctf24_sniff/pi2.jpg Binary files differ. diff --git a/images/crewctf24_sniff/rpi_pinout.png b/images/crewctf24_sniff/rpi_pinout.png Binary files differ. diff --git a/images/deadface23-shattered_dreams-forum.png b/images/deadface23-shattered_dreams-forum.png Binary files differ. diff --git a/layouts/blog/rss.xml b/layouts/blog/rss.xml @@ -1,39 +0,0 @@ -{{- $pctx := . -}} -{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} -{{- $pages := slice -}} -{{- if or $.IsHome $.IsSection -}} -{{- $pages = $pctx.RegularPages -}} -{{- else -}} -{{- $pages = $pctx.Pages -}} -{{- end -}} -{{- $limit := .Site.Config.Services.RSS.Limit -}} -{{- if ge $limit 1 -}} -{{- $pages = $pages | first $limit -}} -{{- end -}} -{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }} -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title> - <link>https://open.crates.im</link> - <description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description> - <generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }} - <language>{{.}}</language>{{end}}{{ with .Site.Author.email }} - <managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }} - <webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }} - <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }} - <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }} - {{ with .OutputFormats.Get "RSS" }} - {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }} - {{ end }} - {{ range $pages }} - <item> - <title>{{ .Title }}</title> - <link>{{ .Permalink }}</link> - <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate> - {{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}} - <guid>{{ .Permalink }}</guid> - <description>{{- .Content | html -}}</description> - </item> - {{ end }} - </channel> -</rss> diff --git a/layouts/blog/section.html b/layouts/blog/section.html @@ -1,10 +0,0 @@ -<!doctype html> -<html lang="en"> -<meta charset="utf-8" /> -<title>{{.Title}}</title> -{{ $style := resources.Get "main.scss" | css.Sass | resources.Minify | resources.Fingerprint }} -<link rel="stylesheet" href="{{ $style.RelPermalink }}"> - -<main> - {{.Content}} -</main> diff --git a/layouts/partials/foot.html b/layouts/partials/foot.html @@ -1,4 +0,0 @@ -<footer> - The content for the site is under <a href="/cc-by-4.0.txt">CC-BY-4.0</a>. - The code is under the <a href="/bsd_license.txt">2-Clause BSD License</a> unless specified otherwise. -</footer> diff --git a/layouts/partials/head.html b/layouts/partials/head.html @@ -1,14 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1" /> - {{ if $.Params.noindex }} - <meta name="robots" content="noindex"> - {{ end }} - <title>{{$.Title}}</title> - <link rel="alternate" type="application/rss+xml" title="RSS" href="https://vineetk.net/blog/index.xml"> - <link rel="icon" type="image/png" href="/AT_terminus.png"> - {{ $style := resources.Get "main.scss" | css.Sass | resources.Fingerprint }} - <link rel="stylesheet" href="{{ $style.RelPermalink }}"> -</head> diff --git a/posts/bctf23_electronical.md b/posts/bctf23_electronical.md @@ -0,0 +1,301 @@ +title: BCTF23 crypto/Electronical (medium) Writeup +date: 2023-10-26 12:00 +--- + +> I do all my ciphering electronically. https://electronical.chall.pwnoh.io/ + +When going to the linked site, you get told to encrypt any message or view the +site's source code. After submitting a message to encrypt, it returns some hex +string. + +The source is: +```python +from Crypto.Cipher import AES +from flask import Flask, request, abort, send_file +import math +import os + +app = Flask(__name__) + +key = os.urandom(32) +flag = os.environ.get('FLAG', 'bctf{fake_flag_fake_flag_fake_flag_fake_flag}') + +cipher = AES.new(key, AES.MODE_ECB) + +def encrypt(message: str) -> bytes: + length = math.ceil(len(message) / 16) * 16 + padded = message.encode().ljust(length, b'\0') + return cipher.encrypt(padded) + +def decrypt(msg: str) -> bytes: + return cipher.decrypt(msg) + +@app.get('/encrypt') +def handle_encrypt(): + param = request.args.get('message') + + if not param: + return abort(400, "Bad") + if not isinstance(param, str): + return abort(400, "Bad") + + print(encrypt(param + flag)) + + return encrypt(param + flag).hex() + +@app.get('/source') +def handle_source(): + return send_file(__file__, "text/plain") + +@app.get('/') +def handle_home(): + return """ + <style> + form { + display: flex; + flex-direction: column; + max-width: 20em; + gap: .5em; + } + + input { + padding: .4em; + } + </style> + <form action="/encrypt"> + <h2><i>ELECTRONICAL</i></h2> + <label for="message">Message to encrypt:</label> + <input id="message" name="message"></label> + <input type="submit" value="Submit"> + <a href="/source">Source code</a> + </form> + """ + +if __name__ == "__main__": + app.run() +``` +It seems that the flag is appended to the user's message and then encrypted with +AES-ECB. The total message is also padded to be a multiple of 16 bytes. + +According to Wikipedia, ECB (electronic codebook) works by dividing a message +into blocks of a certain size (like 16 bytes). The problem however is that ECB +doesn't attempt to make any encrypted block unique like by adding a salt or +nonce, so any blocks of data that are identical would also be identical when +encrypted. Wikipedia also has an interesting example of encrypting an image of +Tux and a mountain (on French Wikipedia) with AES. + +![Tux AES](images/bctf23_electronical-tux_aes.png) + +![Mountain AES](images/bctf23_electronical-mountain_aes.png) + +Through some more searching online, it seems a way to exploit this is with +something called a Chosen Plaintext Attack. Since the message before the flag is +controlled by us the user (attacker?) and the flag is appended to the end, the +provided message can be made in a way that only one byte of the flag needs to be +bruteforced at a time. + +Let's say that this is our message: `thischallengesucksFLAG{5om3_!mp0r74nt_$3cr37}` + +This string is 45 characters, so the server would pad this with 3 \0 characters +to make it evenly divisible by 16 characters. + +``` +b'thischallengesucksFLAG{5om3_!mp0r74nt_$3cr37}\x00\x00\x00' +``` + +We know what "thischallengesucks" is, but FLAG and anything else after is +appended by the server and is what we're trying to find. + +"thischallengesucks" is 18 characters, but if we send a 15 character string, +then the first block to be encrypted would be "thischallengesu?", where ? is the +mystery character. + +For readability purposes, I'm going to use repeated "0" characters needed +instead of "thischallengesucks". + +When passing "000000000000000?" to the server, a certain hex string would be +returned (newlines every 32 characters not included in original): + +``` +b57189530dacbb9c5707c1cb0b044a34 +5377049685bb9553a73e4408565505dd +0c614f69c4749b10f8cbc9c735fd7314 +5a9ae527825603a8eb0dba6a0347a4e5 +``` +Replacing the ? with any other character would result in only the first row being +changed, like with "000000000000000A": + +``` +b2457a857e82a1d5ad919a4bdaf9133a +7835c84bc75d836fad8ca5fbcec086ff +937cf83a682fa26162a65f2295b2b119 +6b398dd6f75e212b1633c5189bdb5689 +``` +Since the other three blocks remained the same, the last character in the +message being sent simply needs to bruteforced with every printable character +until it results in the same block from ?. In this case, that character would be +F: + +``` +b57189530dacbb9c5707c1cb0b044a34 +5377049685bb9553a73e4408565505dd +0c614f69c4749b10f8cbc9c735fd7314 +5a9ae527825603a8eb0dba6a0347a4e5 +``` +``` +(0000000000000, 14 characters long) +5ec61f1209adfeff202edbba28339f83 +4f7cc7a4c0c553380874383e93408678 +ca91d95b091956edb162da583b51051b +33b91ab14b8807348fc98bf223b4b3a5 + +(0000000000000FL, 16 characters long) +5ec61f1209adfeff202edbba28339f83 +4f7cc7a4c0c553380874383e93408678 +ca91d95b091956edb162da583b51051b +33b91ab14b8807348fc98bf223b4b3a5 +``` +Then the 0 left pad would be decreased by one character and the process repeats +until the whole block is done. However, a flag usually won't be just 16 +characters long. I had some difficulty trying to bruteforce the 17th character +and above because I was prepending and appending the zeros within a single block +(between 0 and 15 padded 0s), but that was among a few other issues I had that +were the result of the message I was sending being in the format of "pad + +known_flag + brute_single_char + pad" where this only worked for the first +block. This did not work later because those messages would have the pad bytes +in the middle of the message, which did not go well. + +In the end, I realized that I can check the target block hexstring by sending +only the padded 0 bytes (or anything else of that length) without other +characters and then append my known bytes of the flag and a single other character +to fill that block to brute force that last character. + +A visual representation is this: + +``` +Block size: 8 characters + +7 pad, 0 known +XXXXXXX? +XXXXXXXF + +6 pad, 1 known +XXXXXX?? +XXXXXXFL + +5 pad, 2 known +XXXXX??? +XXXXXFLA + +... + +0 pad, 7 known +FLAG{5o? + +8 known +FLAG{5om +``` +This only decrypts the first block, so how I decrypted each additional block was +by prepending another block of pad characters (blocksize - 1) and repeating the +process. + +``` +7 pad, 7 known +XXXXXXXFLAG{5om? +XXXXXXXFLAG{5om3 + +6 pad, 8 known +XXXXXXFLAG{5om3? +XXXXXXFLAG{5om3_ + +... + +5 pad, 26 known +XXXXXFLAG{5om3_!mp0r74nt_$3cr37? +XXXXXFLAG{5om3_!mp0r74nt_$3cr37} + +... +0 pad, 31 known +FLAG{5om3_!mp0r74nt_$3cr37}\0\0? +FLAG{5om3_!mp0r74nt_$3cr37}\0\0\0 +``` +After some automating help with python, I was able to finally get the flag. + +``` +Flag: bctf{1_c4n7_b3l13v3_u_f0und_my_c0d3b00k} +``` + +My python file to solve this was: +```python +from requests import get +from requests.utils import quote + +# list of characters that will be bruteforced, these are the printable chars +chars = [chr(i) for i in range(ord(' '), ord('~') + 1)] +# nul character is also checked because that's the pad character +chars += '\0' + +def encrypt(msg): + #url = "https://electronical.chall.pwnoh.io/encrypt?message=" + url = "http://localhost:5000/encrypt?message=" + return get(url + quote(msg)).content; + +def calc_padding_for_known(): + # divided by 2 because each hex byte is 2 characters long + cur = len(encrypt("0")) // 2 + + # 16 chosen because that's the padding chosen in app.py on the server + for i in range(2, 16): + tmp = len(encrypt("0" * i)) // 2 + if tmp > cur: + return tmp, tmp - cur, i - 1 + # shouldn't come here + return 0,0,0 + +totalblocks, bs, pad = calc_padding_for_known() + +print(f"Block size of padding: {bs}, {pad}") + +# first block are known to not be the flag (is all 0 being encrypted) +# second block is what's being bruteforced +# third block's last character is unknown and being compared with second block +#msg = "0" * (bs + bs - 1) + "a" * 1 + "0" * (bs - 1) +#cur = encrypt(msg) +#print(cur) +flag = "" +curflag = "" + +tbs = bs * 2 + +for j in range(totalblocks // bs): + for i in range(1, bs + 1): + known = "0" * (bs * (1 + j) - len(flag) - 1) + msg = known + target = encrypt(msg).decode("utf-8") + + print(f"\nNew target message: {msg}") + print("New target message return:") + print('\n'.join([target[A:A + tbs] for A in range(0, len(target), tbs)])) + + target = target[tbs * (0 + j):tbs * (1 + j)] + print(f"New target block: {target}") + + for c in chars: + msg = known + flag + c + print(f"Current character: {c}") + print(f"Current message: {msg}") + print(f"Target block: {target}") + cur = encrypt(msg).decode("utf-8") + print('\n'.join([cur[A:A + tbs] for A in range(0, len(cur), tbs)])) + + print(f"Current block: {cur[:tbs]}") + + if (cur[tbs * (0 + j):tbs * (1 + j)] == target): + flag += c + print(flag) + break + + print("\n") + curflag += flag +print(flag) +``` diff --git a/posts/crewctf24_sniff.md b/posts/crewctf24_sniff.md @@ -0,0 +1,369 @@ +title: CrewCTF2024 misc/Sniff Writeup +date: 2024-08-04 12:00 +--- +## Challenge +### Description +> I came across this mysterious device. So I hooked up my logic analyzer +and recorded somebody using it. (`capture.sol`) +This challenge has two flags in the `flag{}` format +> * The first (easier) is the password that was typed on the keyboard. +> * The second (significantly harder) is what was display on the screen after the password was entered. + +### Images +![Device](https://vineetk.net/images/crewctf24_sniff/device.jpg) + +![Everything](https://vineetk.net/images/crewctf24_sniff/everything.jpg) + +![Raspberry Pi first](https://vineetk.net/images/crewctf24_sniff/pi1.jpg) + +![Raspberry Pi second](https://vineetk.net/images/crewctf24_sniff/pi2.jpg) + +![Logic Analyzer first](https://vineetk.net/images/crewctf24_sniff/logic1.jpg) + +![Logic Analyzer second](https://vineetk.net/images/crewctf24_sniff/logic2.jpg) + +![Display first](https://vineetk.net/images/crewctf24_sniff/display1.jpg) + +![Display second](https://vineetk.net/images/crewctf24_sniff/display2.jpg) + +## Intro +Instead of sleeping, I made the mistake^Wwise decision of looking at my +Discord notification that said there was a hardware challenge in this CTF. It +just so happened that there it was using an ATmega-powered keyboard and an +e-paper screen, and it almost seemed like a coincidence since I was designing +my own keyboard and wanted to interface with an e-paper screen in the near +future. This seemed like a great learning opportunity so I started working on +the two-part challenge. + +There were a few files inside the `dist.zip`, with the most +interesting one being capture.sal which was technically a zip but actually +the analyzer file for Salae. Sadly it seemed to need their proprietary +program to open. + +![Screenshot of Saleae Logic 2, the program used for viewing the dump.](https://vineetk.net/images/crewctf24_sniff/logic2_main.png) + +The first thing I did was figuring out what each channel was connected to +and what it meant. It seemed that the keyboard and display were controlled by +the Raspberry Pi which then seemed to go to the logic analyzer. So I looked +at what each channel was connected to and based on its connected pin on the +Pi, I found its function via pinout.xyz. I ended up with this: + +``` +Channel 0: P03 I2C SDA +Channel 1: P05 I2C SCL +Channel 2: P11 GPIO 17 (busy) +Channel 3: P13 GPIO 27 (reset) +Channel 4: P15 GPIO 22 (data/command) +Channel 5: P21 MOSI +Channel 6: P23 SPI0 SCLK +Channel 7: P24 SPI0 CE0 +``` + +![Raspberry Pi Pinout](https://vineetk.net/images/crewctf24_sniff/rpi_pinout.png) + +## Part 1 +In Logic 2, I opened the I2C analyzer and outputted the dump in the +terminal tab into a file + +![I2C analyzer screenshot in Logic 2 in the Terminal view.](https://vineetk.net/images/crewctf24_sniff/logic2_i2c_1.png) +![I2C analyzer screenshot in Logic 2 in the Data Table view.](https://vineetk.net/images/crewctf24_sniff/logic2_i2c_2.png) +It seemed there was a lot of NUL bytes being sent, probably indicating +that there wasn’t anything during that cycle, and a few seconds later there +were also some other different bytes with NUL and some `0x01` +bytes in between, and these seemed to be printable ASCII. + +``` +read to 0x5F ack data: 0x01 +read to 0x5F ack data: 0x01 +read to 0x5F ack data: 0x66 +read to 0x5F ack data: 0x6c +read to 0x5F ack data: 0x61 +read to 0x5F ack data: 0x67 +read to 0x5F ack data: 0x7b +read to 0x5F ack data: 0x37 +read to 0x5F ack data: 0x01 +read to 0x5F ack data: 0x31 +read to 0x5F ack data: 0x37 +read to 0x5F ack data: 0x66 +read to 0x5F ack data: 0x37 +read to 0x5F ack data: 0x35 +read to 0x5F ack data: 0x01 +read to 0x5F ack data: 0x33 +read to 0x5F ack data: 0x32 +read to 0x5F ack data: 0x7d +read to 0x5F ack data: 0x01 +read to 0x5F ack data: 0x0d +``` + +Filtering out the `0x00` and `0x01` data bytes and +converting to ASCII results in `flag{717f7532}`. + +## Part 2 +![Logic 2 SPI analyzer output.](https://vineetk.net/images/crewctf24_sniff/logic2_spi.png) + +I first outputted the SPI dump from the analyzer into a file and kept only +the `MOSI` and `MISO` columns. + +``` +Time [s],Packet ID,MOSI,MISO +4.108880200000000,0,0x12,0x00 +5.109988000000000,0,0x01,0x00 +5.110044320000000,0,0xF9,0xFF +5.110062800000000,0,0x00,0xFF +5.110081280000000,0,0x00,0xFF +5.110125600000000,0,0x3A,0x00 +5.110167440000000,0,0x1B,0xFF +5.110210120000000,0,0x3B,0x00 +5.110251760000000,0,0x0B,0xFF +``` + +To actually understand what’s going on, I couldn’t find any proper +documentation initially. There wasn’t even a proper datasheet on DigiKey; the +“datasheet” was just a summary of the product. + +![DigiKey “datasheet”](https://vineetk.net/images/crewctf24_sniff/digikey_datasheet.png) + +Then I found the [Python library +source from Pimoroni](https://github.com/pimoroni/inky) of their epaper screens, which is probably what was +used to make this challenge. + +```python +def setup(self): + """Set up Inky GPIO and reset display.""" + if not self._gpio_setup: + if self._gpio is None: + try: + import RPi.GPIO as GPIO + self._gpio = GPIO + except ImportError: + raise ImportError('This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio') + self._gpio.setmode(self._gpio.BCM) + self._gpio.setwarnings(False) + self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF) + self._gpio.setup(self.reset_pin, self._gpio.OUT, initial=self._gpio.HIGH, pull_up_down=self._gpio.PUD_OFF) + self._gpio.setup(self.busy_pin, self._gpio.IN, pull_up_down=self._gpio.PUD_OFF) + + if self._spi_bus is None: + import spidev + self._spi_bus = spidev.SpiDev() + + self._spi_bus.open(0, self.cs_pin) + self._spi_bus.max_speed_hz = 488000 + + self._gpio_setup = True + + self._gpio.output(self.reset_pin, self._gpio.LOW) + time.sleep(0.5) + self._gpio.output(self.reset_pin, self._gpio.HIGH) + time.sleep(0.5) + + self._send_command(0x12) # Soft Reset + time.sleep(1.0) + self._busy_wait() + +def _update(self, buf_a, buf_b, busy_wait=True): + """Update display. + + Dispatches display update to correct driver. + + :param buf_a: Black/White pixels + :param buf_b: Yellow/Red pixels + + """ + self.setup() + + self._send_command(ssd1608.DRIVER_CONTROL, [self.rows - 1, (self.rows - 1) >> 8, 0x00]) + # Set dummy line period + self._send_command(ssd1608.WRITE_DUMMY, [0x1B]) + # Set Line Width + self._send_command(ssd1608.WRITE_GATELINE, [0x0B]) + # Data entry squence (scan direction leftward and downward) + self._send_command(ssd1608.DATA_MODE, [0x03]) + # Set ram X start and end position + xposBuf = [0x00, self.cols // 8 - 1] + self._send_command(ssd1608.SET_RAMXPOS, xposBuf) + # Set ram Y start and end position + yposBuf = [0x00, 0x00, (self.rows - 1) & 0xFF, (self.rows - 1) >> 8] + self._send_command(ssd1608.SET_RAMYPOS, yposBuf) + # VCOM Voltage + self._send_command(ssd1608.WRITE_VCOM, [0x70]) + # Write LUT DATA + self._send_command(ssd1608.WRITE_LUT, self._luts[self.lut]) + + if self.border_colour == self.BLACK: + self._send_command(ssd1608.WRITE_BORDER, 0b00000000) + # GS Transition + Waveform 00 + GSA 0 + GSB 0 + elif self.border_colour == self.RED and self.colour == 'red': + self._send_command(ssd1608.WRITE_BORDER, 0b00000110) + # GS Transition + Waveform 01 + GSA 1 + GSB 0 + elif self.border_colour == self.YELLOW and self.colour == 'yellow': + self._send_command(ssd1608.WRITE_BORDER, 0b00001111) + # GS Transition + Waveform 11 + GSA 1 + GSB 1 + elif self.border_colour == self.WHITE: + self._send_command(ssd1608.WRITE_BORDER, 0b00000001) + # GS Transition + Waveform 00 + GSA 0 + GSB 1 + + # Set RAM address to 0, 0 + self._send_command(ssd1608.SET_RAMXCOUNT, [0x00]) + self._send_command(ssd1608.SET_RAMYCOUNT, [0x00, 0x00]) + + for data in ((ssd1608.WRITE_RAM, buf_a), (ssd1608.WRITE_ALTRAM, buf_b)): + cmd, buf = data + self._send_command(cmd, buf) + + self._busy_wait() + self._send_command(ssd1608.MASTER_ACTIVATE) +``` + +It was also communicating over SPI which seemed to indicate that this was +the proper library. Then I looked at the `setup()` and +`_update()` functions in +`library/inky/inky_ssd1608.py`, and the SPI commands that were +sent in the analyzed dump log matched exactly, including each byte of the LUT +table. + +All the SPI commands used in the library are used with named constants +that are defined `library/inky/ssd1608.py`: + +```python +"""Constants for SSD1608 driver IC.""" +DRIVER_CONTROL = 0x01 +GATE_VOLTAGE = 0x03 +SOURCE_VOLTAGE = 0x04 +DISPLAY_CONTROL = 0x07 +NON_OVERLAP = 0x0B +BOOSTER_SOFT_START = 0x0C +GATE_SCAN_START = 0x0F +DEEP_SLEEP = 0x10 +DATA_MODE = 0x11 +SW_RESET = 0x12 +TEMP_WRITE = 0x1A +TEMP_READ = 0x1B +TEMP_CONTROL = 0x1C +TEMP_LOAD = 0x1D +MASTER_ACTIVATE = 0x20 +DISP_CTRL1 = 0x21 +DISP_CTRL2 = 0x22 +WRITE_RAM = 0x24 +WRITE_ALTRAM = 0x26 +READ_RAM = 0x25 +VCOM_SENSE = 0x28 +VCOM_DURATION = 0x29 +WRITE_VCOM = 0x2C +READ_OTP = 0x2D +WRITE_LUT = 0x32 +WRITE_DUMMY = 0x3A +WRITE_GATELINE = 0x3B +WRITE_BORDER = 0x3C +SET_RAMXPOS = 0x44 +SET_RAMYPOS = 0x45 +SET_RAMXCOUNT = 0x4E +SET_RAMYCOUNT = 0x4F +NOP = 0xFF +``` + +I then noticed that there was a long string of bytes being sent after a +`0x24` which in the library indicated that it was the memory +buffer for the black/white channel ending with a `0x00` +`MISO`, with the yellow/red channel afterward with a +`0x26` `MOSI` and also ended with `0x00` +`MISO` + +``` +... +0x19,0xFF +0x01,0xFF +0x00,0xFF +0x3C,0x00 +0x01,0xFF +0x4E,0x00 +0x00,0xFF +0x4F,0x00 +0x00,0xFF +0x00,0xFF +0x24,0x00 +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +0xFF,0xFF +... +``` + +There also seemed to be two different updates at around 5 seconds and 70 +seconds. + +![Logic 2 SPI analyzer with 0x24 searched to show when each screen update started.](https://vineetk.net/images/crewctf24_sniff/logic2_spi_update_times.png) + +However, the number of bytes written was 4250, which wasn’t the 3812.5 or +2756 bytes I was expecting. This wasn’t divisible by 250 nor 122 and so I was +stuck for a long time. Looking through the library source for more than an +hour with my tired self didn’t help much either. As a last ditch attempt, I +tried converting the raw bytes into an image via Pillow, I used the +`L` mode (`8bpp`) and just got an uninteresting garbled +image. + +![Garbled image reflecting my sadness at being unable to get the flag.](https://vineetk.net/images/crewctf24_sniff/failed_flag.png) + +## Part 2 Part 2: Electric Boogaloo +![Joey asking in the CTF’s Discord about the challenge.](https://vineetk.net/images/crewctf24_sniff/discord1.png) +![Me being surprised in the Discord for my stupidity that I blame on being tired.](https://vineetk.net/images/crewctf24_sniff/discord2.png) + +After waking up and working on the CTF after it ended, my partner asked on +the Discord and found some interesting very helpful information. It turned +out the image was a packed 1bpp image. This meant that each byte in the +memory framebuffer contained 8 pixels (8 bits / 1 bits per pixel = 8 +pixels). + +```python +# under show() +buf_a = numpy.packbits(numpy.where(region == BLACK, 0, 1)).tolist() +buf_b = numpy.packbits(numpy.where(region == RED, 1, 0)).tolist() +``` + +In the Python source, this was shown by `buf_a` and +`buf_b` being packed bits of 1bpp via NumPy. I don’t know much +about NumPy, so this was a skill issue as I initially assumed it was a +complicated way of saving all the black and red pixels into lists. This is a +good reminder that the documentation should be checked for all unfamiliar +functions instead of naively assuming what they seem to do. + +Also in addition to the screen being rotated by 90 degrees, the vertical +resolution is actually 136 pixels and not 120 according to the driver. + +Knowing all this solved all my problems as 4250 * 8 was indeed divisible +by 250 and the actual vertical resolution 136. + +All I had to do was change the Pillow mode when converting the bytes to an +image from `L` (8bpp) to `1` (1bpp) and the (rotated) +resolution from `(250, 16)` to `(136, 250)` and got an +actual image. + +![Extracted image of the display showing the initial message shown in the challenge description.](https://vineetk.net/images/crewctf24_sniff/converted_eink_image.png) + +I used the first updated bytes which was the screen shown in the +challenge’s screenshots. Using the second update’s bytes gave half of the +flag in the black/white channel and the other half in the yellow/red +channel. + +![The flag in the black/white channel.](https://vineetk.net/images/crewctf24_sniff/flag1.png) +![The flag in the yellow/red channel.](https://vineetk.net/images/crewctf24_sniff/flag2.png) + +Each character index in both channels seemed to alternate, so the actual +flag was `flag{ec9cf2b7}`. After I finished writing this writeup +and seeing the two images side-by-side, they probably could’ve been overlayed +after one’s colours are inverted, and is probably what was meant by +“stitching” the channels together. + +## Conclusion +This was my most favourite CTF challenge by far and I learned a lot, +especially about stuff I wanted to learn like how SPI e-paper screens work +and not be lost with I2C. I am personally now curious whether the SPI screens +can be interfaced directly with the MCU instead of going through an +intermediate daughterboard/HAT and how different the protocol for parallel +screens are since they’re much faster and use more pins. diff --git a/posts/csaw23_rebug1.md b/posts/csaw23_rebug1.md @@ -0,0 +1,97 @@ +title: CSAW23 rev/Rebug1 Writeup +date: 2023-09-28 12:00 +--- +> Can't seem to print out the flag :( Can you figure how to get the flag +with this binary? + +An innocent looking binary is given that asks for a string: + +``` +./test.out +Enter the String: rptuainadui +that isn't correct, im sorry! +``` + +This is part of the rev category (which I think is for reverse +engineering). You could bruteforce this yes, but I found it easier +to put this into a decompiler like the ones on [DogBolt (Decompiler +Explorer)](https://dogbolt.org/) to see what it's doing. + +Decompiled main function (via angr): + +``` +int main() +{ + char v0; // [bp-0x448] + unsigned int v1; // [bp-0x41c] + char v2; // [bp-0x418] + char v3; // [bp-0x408] + unsigned long long v4; // [bp-0x18] + unsigned int v5; // [bp-0x10] + unsigned int v6; // [bp-0xc] + unsigned long long v8; // rax + + printf("Enter the String: "); + __isoc99_scanf("%s", (unsigned int)&v3); + for (v6 = 0; (&v3)[v6]; v6 += 1); + if (v6 == 12) + { + puts("that's correct!"); + v4 = EVP_MD_CTX_new(); + (unsigned int)v8 = EVP_md5(); + EVP_DigestInit_ex(v4, v8, 0x0, v8); + EVP_DigestUpdate(v4, "12", 0x2, "12"); + v1 = 16; + EVP_DigestFinal_ex(v4, &v2, &v1, &v2); + EVP_MD_CTX_free(v4); + for (v5 = 0; v5 <= 15; v5 += 1) + { + sprintf(&(&v0)[2 * v5], "%02x", (&v2)[v5]); + } + printf("csawctf{%s}\n", (unsigned int)&v0); + return 0; + } + printf("that isn't correct, im sorry!"); + return 0; +} +``` + +This along with the rest of the decompiled binary can't be simply compiled again +as-is because there are a few issues, like the OpenSSL functions being called +having an extra argument added to the end. + +When looking at the functions being called, it seems that the flag is just an +md5 of the number 12. The program also seems to give the flag itself if you give +it the character with the ASCII value of 12 (form feed). + +The line that that has the data being checksummed is this: + +``` +EVP_DigestUpdate(v4, "12", 0x2, "12"); +``` + +I did try piping the form feed character via printf to the binary, but it did +not like that, so it seems that the only way to get the flag is through another +way. + +While you could just create a very simplified version of the decompiled source +with OpenSSL's crypto library (which is what I did originally), it's much easier +to just pass the number 12 to a pre-installed md5 command (md5 on OpenBSD, +md5sum on Linux). + +``` +$ echo -n 12 | md5 +c20ad4d76fe97759aa27a0c99bff6710 +``` + +This CTF's flags were in the format of csawctf{somethinghere}, as also seen in +the decompiled source, so the actual flag was this: + +``` +csawctf{c20ad4d76fe97759aa27a0c99bff6710} +``` + +This was my first time doing any decompilation of a program, and I think this +was a good start to learn reverse engineering. + +``` +\ No newline at end of file diff --git a/posts/deadface23_hostbusters3.md b/posts/deadface23_hostbusters3.md @@ -0,0 +1,37 @@ +title: "DEADFACE CTF 2023 Host Busters 3 Writeup" +date: 2023-10-26 12:00 +--- +> Continue characterizing the machine. Is there any way you can +escalate to a user that has permissions the vim user does not have? Find +the flag associated with this user. +Submit the flag as `flag{flag_here}`. + +``` +vim@ghost404.deadface.io letmevim +``` + +You first login to vim, which has vim open. Then you escape from it like you +did in the OverTheWire Bandit challenges with `:set shell=bash` and `:shell`. Now you have a proper shell over SSH. + +The first thing I looked at after mistaking Host Busters 1's key in the home +directory as 3 was look at what other user home directories there were by +running `ls /home`. I saw there were a few users, notably `gh0st404` and +`spookyboi`. + +`gh0st404`'s user home directory had his OpenSSH private key as +world-readable and in plain sight not in his `.ssh` hidden +directory. It being world-readable would have had OpenSSH scream at you, but +them being stupid was good for us. + +So, once you use that SSH private key to login as `gh0st404`, +you can check the contents of hostbusters3.txt and you got the flag. + +``` +cat hostbusters3.txt +``` + +> "This is why you should have come to the Monday meetings for OverTheWire." +~Joey, FPUSEC President + +[Here's](https://asciinema.org/a/ZhQQwEVwgaqtGCuaqRf6NWu8N) an +asciinema of the entire thing in action. diff --git a/posts/deadface23_shattered-dreams.md b/posts/deadface23_shattered-dreams.md @@ -0,0 +1,166 @@ +title: DEADFACE CTF 2023 Shattered Dreams Writeup +date: 2023-10-26 12:00 +--- +> DEADFACE is on the brink of selling a patient's credit card details from the +Aurora database to a dark web buyer. Investigate Ghost Town for potential leads +on the victim's identity. + +A huge hint was dropped immediately, so I went to Ghost Town to find a thread +titled "We got a potential buyer". + +The flag's format is `flag{Firstname Lastname}`. + +lilith, the original poster of the thread, said the victim's SHA1 hash we need +to look for is "911d1fc5930fa5025dbc2d3953c94de9e4773584" and showed how she +calculated that, including the (lack of) delimeter. + +![https://ghosttown.deadface.io/t/dark-web-dumps-anyone/101](https://vineetk.net/images/deadface23-shattered_dreams-forum.png) + +So, we can easily bruteforce getting this SHA1 hash by repeating what lilith +did. + +The first three fields (card number, expiration, CCV) are values from the +billing table and the rest of the fields is all the fields in the patient +table. + +```sql +CREATE TABLE `billing` ( + `billing_id` int(11) NOT NULL AUTO_INCREMENT, + `patient_id` int(11) NOT NULL, + `credit_type_id` int(11) NOT NULL, + `card_num` varchar(24) NOT NULL, + `exp` varchar(8) NOT NULL, + `ccv` varchar(4) NOT NULL, + PRIMARY KEY (`billing_id`), + UNIQUE KEY `card_num` (`card_num`), + KEY `fk_billing_patient_id` (`patient_id`), + KEY `fk_billing_credit_type_id` (`credit_type_id`), + CONSTRAINT `fk_billing_credit_type_id` FOREIGN KEY (`credit_type_id`) REFERENCES `credit_types` (`credit_type_id`) ON DELETE CASCADE, + CONSTRAINT `fk_billing_patient_id` FOREIGN KEY (`patient_id`) REFERENCES `patients` (`patient_id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=14443 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +... +CREATE TABLE `patients` ( + `patient_id` int(11) NOT NULL AUTO_INCREMENT, + `first_name` varchar(32) NOT NULL, + `last_name` varchar(64) NOT NULL, + `middle` varchar(8) DEFAULT NULL, + `sex` varchar(8) NOT NULL, + `email` varchar(128) NOT NULL, + `street` varchar(64) NOT NULL, + `city` varchar(64) NOT NULL, + `state` varchar(8) NOT NULL, + `zip` varchar(12) NOT NULL, + `dob` date NOT NULL, + PRIMARY KEY (`patient_id`), + UNIQUE KEY `email` (`email`) +) ENGINE=InnoDB AUTO_INCREMENT=18542 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +``` + +Since there are no delimeters, they can just be concatenated with each other +and then piped to sha1. The difficult part I had was properly concatenating +those values because I was not able to read the MySQL dump with sqlite3 nor +mariadb. + +I noticed that each of the rows that were inserted into the tables were +delimited by a comma, similar to CSV. + +```sql +INSERT INTO `patients` VALUES (8151,'Lorrayne','Covey','E','Female','lcovey0@wunderground.com','40411 Old Shore Street','Houston','TX','77201','1985-02-08'),(8152,'Eddy','Omand','S','Female','eomand1@mysql.com','454 Pine View Alley','Columbus','OH','43226','1959-09-29'),(8153,'Renard','Berre','O','Male','rberre2@friendfeed.com','3496 Merrick Center','Pittsburgh','PA','15235','1978-12-05'),(8154,'Galven','Nardrup','M','Male','gnardrup3@mac.com','0 American Road','Denver','CO','80241','1984-04-09'), ... +``` + +So I was able to easily convert it into a CSV with the following command: + +```bash +grep 'INSERT INTO `patients`' aurora.sql \ + | sed 's/^INSERT[^(]*//' \ + | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' +``` + +Part of the output is now: + +``` +...18532,'Becka','Hurlin','T','Female','bhurlin80d@yolasite.com','58 Amoth Way','Ventura','CA','93005','1953-11-14' +18533,'Aluin','Horwell','O','Male','ahorwell80e@cbc.ca','3 Oriole Terrace','Miami','FL','33190','1984-06-24' +18534,'Glennis','Walder','R','Female','gwalder80f@cnet.com','966 Packers Hill','Topeka','KS','66617','1950-01-21' +... +``` + +One problem I had when I used tr to replace ( with \n was that one of the names +had () in their name for some reason, which messed up the concatenating of the +two files to get the hash. I originally just manually edited it, but the above +with awk is cleaner. The same goes with the 'INSERT INTO ...' part messing things up for the same reason. I didn't save my ~/.ksh_history file with the +commands I ran, so this is a non-ugly version I remade with more awk. + +To properly concatenate the data fields, the comma and single quotes should +also be removed, which tr can be used for unlike before. + +```bash +grep 'INSERT INTO `patients`' aurora.sql \ + | sed 's/^INSERT[^(]*//' \ + | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' \ + | tr -d "'," >patients_.txt +``` + +Part of the output prior to being written to a file is now: + +``` +18527TannerMasselinAMaletmasselin808@google.es10080 Reindahl CourtBoca RatonFL334871957-08-15 +18528MerrelYeudeDMalemyeude809@ca.gov7934 Katie PassSaint PaulMN551881951-04-07 +18529JeffVan BaarenMMalejvanbaaren80a@sphinn.com58097 Autumn Leaf DriveNew OrleansLA701421984-01-13 +``` + +It is written to a file so that it can be easy to concatenate both the billing +and patient data by using the paste command. + +The next part is doing the same with the billing data. Unlike with the patient +data, only three fields from the billing table is used instead of all, so cut +or awk can be used with the delimeter set to a comma. + +Before that, we need to know what index (base 1) the three fields are at. The +credit card number, expiry date, and ccv are fields 4, 5, and 6. + +```bash +grep 'INSERT INTO `billing`' aurora.sql \ + | sed 's/^INSERT[^(]*//' \ + | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' \ + | cut -d, -f4,5,6 \ + | tr -d "'," >billing_.txt +``` + +Some of the output looks like + +``` +51087507745678202025-01403 +50483770976260922023-07242 +50483739134688352023-12501 +``` + +Both tables with the fields have been parsed and saved to two different files, but simply using cat on both the files would simply print the contents of the second file after the first file has finished printing, but we need each line of both the files to be joined together! That's where the paste command comes in. It combines each line of its input files, which is exactly what is required. + +These merged lines are then fed into sha1, and finally grep can be used to look for the hash we need and print the victim's name if it shows up. + +```bash +target_hash="911d1fc5930fa5025dbc2d3953c94de9e4773584" + +paste billing_.txt patients_.txt | tr -d '\t' \ + | while read line; do + echo -n "$line" | sha1 \ + | grep "$target_hash" && echo "$line" && break + done +``` + +The outputted line of the victim who had the same hash is: + +``` +50483743238485412026-0498316314BertonLuchettiXMalebluchetti6ar@taobao.com39 Meadow Ridge TerraceClevelandOH441251964-10-29 +``` + +So, the victim is Berton X. Luchetti, and the flag is `flag{Berton Luchetti}`. + +This challenge would probably have been easier if I was able to use proper SQL +commands, but I couldn't do that and standard UNIX tools saved the day. I did +the exact same process of parsing the tables for all the other SQL challenges +and I found it funny that I solved all of them without needing to run a single +SQL command (partly because they didn't load the file). + +``` +\ No newline at end of file diff --git a/posts/kobo_clara-custom-distro.md b/posts/kobo_clara-custom-distro.md @@ -0,0 +1,281 @@ +title: Kobo Clara HD Custom Linux Distro/RootFS +date: 2021-07-22 12:00 +--- + +These are just some notes I made when creating my own mini-distro after +wanting something more custom than just using buildroot or making the +official firmware more slim. For people other than me, I suggest +looking through (C)LFS or running postmarketOS instead once this +reader's pull request[1] gets integrated into upstream. + +Two things that'll greatly help with this is having serial terminal +access with the four uart pins near the top right in the back of the +reader, near the uSD card slot (I don't connect the 5V pin as my reader +doesn't really turn on anything other than the power LED). I suggest +maybe soldering female pin headers to there to make your life easier +(you can later cut out a hole in the back cover or desolder the headers +once you're done). Other than that, I suggest installing QEMU with ARM +userspace to test programs that you have built or running them on a +separate ARM device like a Raspberry Pi. + +## Prelude +Ever since I learnt that the official firmware for the Clara was just +using a modified Linux kernel with busybox as coreutils and many other +libraries, I just knew that I had to minimize it. I also saw that it +was using glibc for it's libc, which I really dislike as statically +linking C programs against it was a pain in my experience, compared to +something like musl and uclibc. It's also much larger than them and I +don't use any of glibc extensions so it seemed like a waste of space to +me. + +Initially when I replaced Nickel with Plato, I was able to shave about +100 MiB after I removed /usr/local (which contains Nickel, Qt and a few +other things), from 189 MiB to 74 MiB, but I still wanted to make it +smaller. + +Using buildroot, I was able to get it under 2 MiB (!!) which was a +little less than half the size of an uncompressed armhf Alpine Linux +minirootfs (4.9M for 3.14). With Busybox, it was pretty much working +out of the box, with serial terminal access! But waiting around 15 +minutes for the toolchain to build each time I wanted to change +something in the rootfs took way too long, although it could've been +minimized if I used ccache with a fairly large cache size. I still +found that it compiled and installed a lot of things I wouldn't be +using (particularly in /usr) even after disabling almost all of the +third-party packages. + +I've uploaded the config file and the resulting rootfs for +buildroot 2021.05. The root password by default is changeme. +EDIT 2022-10-21: gone, build it yourself + +Of course the rootfs I got from buildroot nor me making the official +firmware smaller is the point of this article, and the actual point is +making one yourself! (or rather what I did to make my own) + +## Cross-toolchain +For now as of July 22, 2021, I'm using my distro (Void Linux)'s +packaged cross toolchain for armhf musl, but eventually I would be +using my own. + +I'm not compiling off of the device itself as it would be somewhat slow +for bigger programs, which is currently primarily the Linux kernel, +U-Boot, and the toolchain itself, considering that the ereader's CPU +(Freescale i.MX 6SLL) is a single core running up to 1 GHz. Including +the development tools and headers would also take up more space on the +device itself, and since the terminal can currently only be accessed +through it's serial/uart pins, I don't think it's ideal. + +TODO: include steps to create own toolchain (probably based off of gcc +4.7.3 as that doesn't require c++) + +## Building the rootfs +Assuming you made a new filesystem on your rootfs's partition, it'll +likely be empty with no directories you'd expect to find on a regular +distro. So you'll just have to make them. +cd /path/to/rootfs +mkdir bin dev etc proc sbin + +Your binaries would usually go in /bin, the uSD card, ttymxc0, and +other devices would go in /dev, felker init's default program/script to +execute is usually in /etc/rc, /proc is optional but I have it mounted +to see what is currently mounted through /proc/mounts (or mount(1) +without any arguments) as well as to see my disk usage through df(1). +/sbin is there to place the init in as /sbin/init is the default init +path the kernel looks at. + +## toybox +Now on to the main part of the distro, the userspace. I intend to keep +it fairly minimal so I've chosen to use toybox along with a slightly +modified version of felker (musl dev)'s init[2], as well as dash[3] as +the main shell since toybox doesn't include one as of 0.8.5 (though +it'll probably be there by 1.0). I'll also be statically linking all +the programs that'll be used so I wouldn't have to worry about shared +libraries not being included/copied over, and also including LTO for +slightly faster binaries. Originally, I tried going with sinit, sbase, +and ubase but I was having trouble getting serial terminal access with +getty to /dev/ttymxc0 (the default serial tty, at least with the +vendor kernel). I didn't have this problem with busybox's and toybox's +getty however. My config for toybox was also about 81K smaller than my +trimmed sbase-box and ubase-box (352K compared to 267K+166K) where I +removed programs that I won't use from ${BIN} in their respective +Makefiles. +EDIT 2022-10-21: also gone + +First I suggest exporting some environment variables to set the +toolchain used as well as enabling static linking and LTO. + +``` +export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc +export CC="${CROSS_COMPILE}gcc" +export LDFLAGS="--static" +export CFLAGS="-flto -static" +export ARCH=arm # for compiling the linux kernel +``` + +To compile toybox, get the source from +https://landley.net/toybox/downloads/ (or clone the upstream repo). +Then run make menuconfig (optionally with make defconfig before it) and +change it as you see fit. Personally, I disabled most of the programs I +wouldn't use and kept only the ones that'll help with fixing a problem. +Finally, make sure to run make. + +``` +make defconfig +make menuconfig +make +``` + +To move it to your rootfs and set it's symlinks, you could probably run +make install after setting PREFIX to your rootfs's /bin directory, but +I did it manually. + +``` +# automatic (didn't test, check README) +make PREFIX=/path/to/rootfs/bin/ install + +# (semi?) manual +cp toybox /path/to/rootfs/bin + +# add symlinks if doing manual and you want them +cd /path/to/rootfs/bin +for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done +``` + +## dash +Also as of toybox 0.8.5, a shell still isn't included (probably would +be included by 1.0 according to scripts/install.sh as well as a few +other programs like gzip), so a separate shell would need to be built. +Any can be used but dash would be shown as an example as I was able to +get a static binary without too much trouble. + +First obtain the source[3] and cd into its +untarred directory. Assuming your CC and CFLAGS are set, you can run +these steps: + +``` +autoreconf -fiv +./configure --host=$CROSS_COMPILE --with-libedit +make +${CROSS_COMPILE}strip src/dash +``` + +As this is going to be used as the main shell, I've decided to just +copy it to /bin/sh in the rootfs directory, though copying it there but +as /bin/dash and /bin/sh being symlinked to dash is also an option. + +``` +cp src/dash /path/to/rootfs/bin/sh +# or +cp src/dash /path/to/rootfs/bin +cd /path/to/rootfs/bin +ln -s dash sh +``` + +## felker's init +The init is just a single file that you can get from felker's site[2] +or the gist on github[7]. I haven't had a good experience with the +default startup program (/etc/rc) as a shell script with execve() run +on it so I'd change it to execvp() and remove the third (specifies +environment). To compile and install the init, all you need to do is +run: + +``` +$CC $CFLAGS -o init init.c +cp init /path/to/rootfs/sbin +``` + +Instead of /etc/rc being a shell script, you can also make a C program +that does whatever you think is needed for a proper startup. I'll still +use a shell script though which is linked here. +EDIT 2022-10-21: you get the idea, it's gone. + +## /etc/passwd +Copying the rootfs's contents to your device's/uSD card's root +partition and then turning the device on should now work with a login +prompt shown in the serial terminal. However, you probably wouldn't be +able to login to any user. So you'll have to create a file at +/path/to/rootfs/etc/passwd. For an empty password to root, you can use +this, though I suggest setting a password as soon as you login: + +``` +# in rootfs's /etc/passwd +root::0:0:root:/root:/bin/sh +``` + +With the passwd file created/updated, you should now be able to login +to root after the rootfs is copied to your uSD card. Your rootfs so far +should now be around 550-560K, which is much much smaller than the +original firmware's, though it'll likely be much larger to maybe a few +megabytes once a proper reader software is added. + +## Custom Linux Kernel +WARNING: I haven't actually gotten the kernel to load in u-boot yet. It +just hangs in the "Starting kernel ..." step and the init doesn't get +loaded, so I'm assuming the kernel itself isn't either. If anyone out +there has gotten a custom kernel working in the Kobo Clara HD, please +send me an email or message on xmpp. + +UPDATE Jul 28, 2021: Gave up on it as I just couldn't get any kernels I +built (both vendor and akemnade's mainline) to boot. But neither did +postmarketOS boot beyond the initial initramfs messages without the log +file being created. So I'll revisit this for later. + +EDIT 2022-10-21: I have gotten this working, but have been unable to +get Plato build for musl, so I will have to either continue fighting +with the crab or create my own with fbink, as that still works. +Separate article on this later. + +My next big step is compiling my own kernel for the Clara HD. With the +default configuration built for the vendor kernel, it appears to be +about 3M, so my goal is to build a kernel that is smaller than that +while retaining only the functionality that I need. I'm also not going +to include networking support as that is unneeded for my purposes, but +I suggest just keeping it if you're unsure. The wifi driver for the +Kobo Clara HD is available as an out-of-tree driver[8]. + +You should first obtain the kernel source, with two main options, the +vendor kernel[9] and the mainline kernel (with akemnade's +patches)[10]. For the latter, you need to clone the repo and switch to +the latest kobo/drm-merged branch (kobo/merged-5.13 as of July 25, +2021). + +After you've got them and assuming the CROSS_COMPILE and ARCH +environment variables are set, you'd want to configure the kernel. + +I had a hard time compiling the vendor kernel with many things +disabled, so I've kept my config somewhat similar to the default +config. The config I used is available here (EDIT: dead). + +``` +make menuconfig +make zImage +``` + +Assuming it compiles properly and arch/arm/boot/zImage exists, all +that's needed to is to write it to your uSD card at the 1M offset. +dd if=/path/to/kernel/zImage of=/path/to/uSDdev bs=512 seek=2048 + +## Custom U-Boot +I have not done this yet, nor really plan to, but if you do manage to +compile the Kobo's vendored u-boot source, then all you'd have to do to +install it is: + +``` +dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 +``` + +If I remember correctly, this command was included in an older +firmware's startup script/rcS for updating udev, and it should still +work. + +## Links +[1]: https://gitlab.com/postmarketOS/pmaports/-/merge_requests/2334 +[2]: https://ewontfix.com/14 +[3]: https://git.kernel.org/pub/scm/utils/dash/dash.git +[4]: https://github.com/akemnade/linux/tree/kobo/merged-5.13 +[5]: https://misc.andi.de1.cc/kobo/uboot-env.txt +[6]: https://misc.andi.de1.cc/kobo/ +[7]: https://gist.github.com/rofl0r/6168719/raw/183525e0f0007169a49392b21ceee5b507e3aee8/init.c +[8]: https://github.com/jwrdegoede/rtl8189ES_linux/tree/rtl8189fs +[9]: https://github.com/kobolabs/Kobo-Reader/blob/master/hw/imx6sll-clara/kernel.tar.bz2 +[10]: https://github.com/akemnade/linux/tree/kobo/drm-merged-5.12 diff --git a/posts/kobo_clara-nickel.md b/posts/kobo_clara-nickel.md @@ -0,0 +1,242 @@ +title: Kobo Clara HD Notes for Nickel +date: 2021-01-13 12:00 +--- + +My ereader of choice is the Kobo Clara HD and I particularly like it +because my eyes hurt less when reading for long periods of time +compared to when I read on my phone or when I still had my iPad. It +also had much longer battery life and only need to charge it about once +every two weeks when I read for about 4 hours on average daily. + +However, the two notable things I don't like about it is it's included +telemetry, like using Google Analytics by default and keeping a unique +salt + +Spyware/Anti-Features: +- Google Analytics (a lot of actions, if not everything, is sent to +Google) +- Auto-update by default + - I prefer being able to review what the new update provides and + choose not to apply it + - I don't like the new redesign in firmware v4.23.15505 + +I'm also assuming your Kobo reader and it's SD card's device file would +be would located at `/dev/sdf` and be mounted at `/mnt/kobo`. + +If you're going to not be using Nickel and instead be using something +like [Plato](https://github.com/baskerville/plato), there's a newer version of this article available +[here](./kobo-clara-plato.html), but the notes are for ~KSM~ loading Plato directly and not +though k/fmon because I don't want to load Nickel if I'm already using +a different reader. + +## Upgrade/Backup Included SD Card +While the included 8GB microSD card is decent for storing your ebook +library that may not have a lot of images, that would likely not be +enough if you were aiming to read some comics on your ereader as they +can be pretty big (quite a few of mine are over a gigabyte, with some +over. Luckily, you can replace the microSD card with another one. + +Before upgrading, you should backup the SD card to into an image file +so the filesystem would be preserved when putting the contents of the +image on the new SD card. I'm using the command dd but there might be +another program doing the same thing. Even if you're not going to +upgrade, I still suggest to backup the SD card in case something goes +wrong. +```sh +dd if=/dev/sdf of=kobo_sd.img conv=sync +``` + +After this is done, you can plug in your new SD card and reimage +kobo_sd.img onto it. With dd, you can do something like: +```sh +dd if=kobo_sd.img of=/dev/sdf conv=sync +``` + +Checking it's partition table via lsblk or fdisk -l should show three +partitions. If you replaced the SD card with something bigger, than you +should resize the third partition. + +## Bypassing Registration On Setup +When setting up your Kobo, you will be asked to sign into a Kobo +account. There are other options like logging in via Google, Walmart, +and other stores, but I don't like having to login to a device that +would likely not be connected to the public internet. Fortunately, you +can bypass this by choosing that you cannot connect to a Wi-Fi network +and mount your Kobo to your computer. In, `.kobo/KoboReader.sqlite`, you +can run: +```sh +echo "INSERT INTO user(UserID,UserKey) VALUES('1','');" \ + | sqlite3 KoboReader.sqlite +``` + +This way you don't have to install their application just to be able to +use your device. + +Note: Do not try doing this when you still have your SD card mounted +before you setup your device. The device's screen would likely not +update, at least on an early firmware version like v4.7.10733. + +## Blocking Google Analytics and other Telemetry +Just adding 0.0.0.0 analytics.google.com to `/etc/hosts` may be enough to +block most of the telemetry from being sent. However, you can try +intercepting what connections your Kobo is making via mitmproxy set to +transparent mode or using a hosts file that blocks all connections to +Google (but not necessarily to Kobo's servers) like [Baobab's hosts file](https://codeberg.org/baobab/hosts) +[(raw)](https://codeberg.org/baobab/hosts/raw/branch/master/hosts). +EDIT 2022-10-21: Baobab has deleted his account from Codeberg for quite a +while, so these two links are dead. Instead, I now recommend [Steven Black's](https://github.com/StevenBlack/hosts) +instead [(raw)](https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts). + +To put the hosts file without root (which will be detailed in another +section), you can make a directory called etc, put the hosts file in +there, and tar it into a file called KoboRoot.tgz. +```sh +mkdir etc +wget -O etc/hosts https://codeberg.org/baobab/hosts/raw/branch/master/hosts +tar czvf KoboRoot.tgz etc +cp KoboRoot.tgz /mnt/kobo/.kobo/ +``` + +When you move a tar file with that name into your Kobo's .kobo folder, +it's contents gets untarred into it's root at `/` when the device is +turned on again, which is usually done for their updates but can be +used for custom files like this and gaining root access. + +## Gaining Root Access via Telnet +To gain root access, we first need to get the `/etc/inittab` and +`/etc/inetd.conf` which you can get from mounting the SD card's first +partition into your computer (the second partition seems to be like a +backup). You should copy those two files into a folder called etc +somewhere (probably not on the SD card). + +In the `etc/inittab` file, you should add these two lines: +``` +::sysinit:/etc/custominit.sh +::respawn:/usr/sbin/inetd -f /etc/inetd2.conf +``` + +You would want to rename the `etc/inetd.conf` file you copied into +`etc/inetd2.conf` (or whatever the custom inetd.conf's filename is) and +when editing that, you should add: +``` +23 stream tcp nowait root /bin/busybox telnetd -i +``` + +However, if there is already a commented line for root telnet in the +inetd2.conf, you should probably still add the above line and ignore +the commented line as that may or may not work (didn't for me). + +To actually start inetd, you should add these lines somewhere in +`/etc/custominit.sh`: +```sh +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts +/usr/sbin/inetd /etc/inetd2.conf +``` + +After that, you just have to tar the `etc/` folder again and copy it to +your Kobo's onboard/third partition's `.kobo` folder. +```sh +tar czvf KoboRoot.tgz etc +cp KoboRoot.tgz /mnt/kobo/.kobo/ +``` + +Now you could put your SD card back into your Kobo provided that they +are already unmounted and turn your Kobo back on. + +After connecting to the WiFi, simplying telnetting (?) into your Kobo +and logging in as root should give you a root shell. :D +```sh +telnet $KOBO_IP +``` + +By default, root has no password so you should change it with passwd. + +## Getting SSH and SFTP access via Dropbear +I'm using Dropbear instead of OpenSSH because it's better suited for +embedded hardware like the Kobo Clara HD. Obviously we can't copy a +binary compiled for amd64 or whatever architecture your compiling +computer is running so we would have to cross-compile for our ereader. + +Fortunately, we are not required to cross-compile `gcc`/`clang` and friends +as we can simply download the linaro arm toolchain which has the +binaries for gcc and others included. You could get the toolchain +[here](https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/) and you should get the release that matches your host's + +architecture. After untarring the file, you should also set your PATH +variable to the toolchain's `bin/` folder so you don't have to manually +set the CC and CXX variables when building Dropbear. + +```sh +wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz +tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz +export PATH=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH +``` + +Now you could get the source for Dropbear and cross-compile it. The +source can be found on their [homepage](https://matt.ucc.asn.au/dropbear/dropbear.html) or [github](https://github.com/mkj/dropbear/releases) repo. +```sh +wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2020.81.tar.bz2 +tar xvf dropbear-2020.81.tar.bz2 +cd dropbear-2020.81 +./configure --enable-static --host=arm-linux-gnueabihf +# MULTI=1 combines the binaries like busybox does and is also smaller in size +make MULTI=1 PROGRAMS="dropbear dropbearkey" +``` + +Now you only need to copy the dropbearmulti binary over to your Kobo. +What I've done is running `python3 -m http.server` and downloading the +file onto my Kobo but you could also just copy it onto the microSD +card. +```sh +wget your.computer.ip:8000/dropbearmulti +chmod +x dropbearmulti +mv dropbearmulti /usr/bin +cd /usr/bin +# below are optional but dropbear(key) would be an argument for dropbearmulti +ln -s dropbearmulti dropbear +ln -s dropbearmulti dropbearkey +``` + +Now you only need to generate the host keys. My client key is ed25519 +so I'm not going to generate the others. +```sh +mkdir /etc/dropbear +dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key +dropbear -F -r /etc/dropbear/dropbear_ed25519_key +``` + +Now you could `ssh` into your Kobo and login as `root`. Remember to change +`root`'s password beforehand though if you haven't already! I suggest +copying your public key to your Kobo via `ssh-copy-id` so you don't have +to enter root's password all the time and so password-based logins can +be disabled in dropbear. + +To start it on boot, you could add the following line to +`/etc/inetd2.conf`: +``` +22 stream tcp nowait root /usr/bin/dropbearmulti dropbear -i -r /etc/dropbear/dropbear_ed25519_key +``` + +For some reason, the symlink wasn't resolving for me inetd so I had to +call the multi-binary directly. You could also add the command/args +into `/etc/custominit.sh`. + +## FTP Access +If you don't or can't use sftp or scp for some reason, there's always ftp :D +There's a ftp daemon included in busybox so all we have to do is enable it +in `/etc/inetd2.conf`: +``` +21 stream tcp nowait root /bin/busybox ftpd -w -S / +``` + +This would share the entire filesystem so you may or may not want to +restrict the shared directory to maybe just your ebook directory +(`/mnt/onboard`) and move the files out via `telnet` or `ssh`. +EDIT 2022-10-21: A chroot would also work. + +## References and Other Links +- [Rémy's notes on hacking a Kobo Aura H2O](https://remy.grunblatt.org/kobo-aura-h2o-electronic-reader-hacking.html) +- [Ying's notes on bypassing registration and setting up telnet, ssh, etc.](https://yingtongli.me/blog/2018/07/30/kobo-rego.html) +- [MobileRead forum thread on disabling Google Analytics on the Kobo Touch](https://www.mobileread.com/forums/showthread.php?t=162713) +- [MobileRead wiki on hacking the Kobo Touch](https://wiki.mobileread.com/wiki/Kobo_Touch_Hacking) diff --git a/posts/kobo_clara-plato.md b/posts/kobo_clara-plato.md @@ -0,0 +1,128 @@ +title: Kobo Clara HD Notes for Plato (and KSM) +date: 2021-03-27 12:00 +--- + +These are my notes for getting Plato on the Kobo Clara HD from scratch +as well as some notes for getting KSM to work, but I now boot directly +into Plato instead of through KSM. + +Previously, I didn't really like using KOReader because it was kind of +slow and was written in Lua. At the time of using Plato, it seemed nice +but it didn't cover thumbnails for books, which while it is a minor +detail, I find books easier to be recognized with a cover thumbnail in +addition to their title. This was added in release 0.9.10 but as an +optional feature which I didn't somehow see until recently when I +retried it. HOWEVER again, I didn't like using k/fmon as I had to still +use Nickel to get back into KOReader/Plato/whatever alternate reader +when I wanted to go away from using Nickel. + +&lt;ignore&gt; +That was when I found out about KSM and how there was a working version +for the Clara HD. KSM is like an alternate bootloader for the Kobo +readers and it apparently doesn't work very well with newer models like +the Clara HD and up, but someone got it to work with those devices. +[KSM 09](https://www.mobileread.com/forums/showthread.php?s=c34e41df391c61810a6b06f991c29168&t=293804) is apparently not maintained anymore and I'm not sure if KSM +10 is being developed or not since I'm pretty sure it's closed source. + +> Development and support for KSM stopped some time ago. Therefore, do +> not use it! + +"That sign can't stop me because I can't read!" - Me imitating D.W. +from the PBS Kids cartoon Arthur on Mar. 26, 2021 when I saw that it +can be used on my Kobo + +The latest firmware version that KSM sort of supports is v4.25.15875 +but it can probably work with a newer version like v4.26+ that would +likely only need a couple changes to /etc/init.d/rcS, if any changes +were needed at all. I'll be using v4.26 for the rest of this +article/guide. +&lt;/ignore&gt; + +Recently, after seeing how my Kobo boots into KSM and Nickel through +the rcS file, I realized that I could've instead just booted directly +into Plato, and plato.sh (the script that runs Plato) has a standalone +option that supports just that! The KSM notes are still going to be +here in case someone still wants to use KSM. + +## Installing Plato (or probably any other reader like KOReader) +This part probably applies to any other reader other than Plato like +KOReader but I haven't personally tested them. All you have to do is +[get the latest release](https://github.com/baskerville/plato/releases/latest) at Plato's repo and unzip it's contents into +a folder called plato in /path/to/kobo/mount/.adds, the latter folder +of which should have already been created by KSM if you are using that. +If you are using KSM, there should be a new option below "start nickel" +called "start plato" when you have rebooted the device. Read below if +you aren't using KSM. + +## Loading Plato on Boot +Since I don't want to load Nickel only to load into another reader like +the recommended options in Plato's forum thread (kfmon, fmon, and +NickelMenu) suggest, I noticed that I could have booted into Plato +directly. The only requirements for doing this having access to the +rootfs, so either through a telnet/ssh session, or having the sd card's +root/first partition mounted to your computer, or just ftp/rsyncing the +files to your Kobo. + +First I suggest making a copy of rcS if you haven't already in case an +update overwrites it. My copy is named custominit.sh. Next you'll want +the Kobo's /etc/inittab to boot with custominit.sh instead of rcS: +/etc/inittab: + +``` +#::sysinit:/etc/init.d/rcS +::sysinit:/etc/custominit.sh +``` + +The rest of the lines don't need to change. Then you should open +custominit.sh in your favourite editor to add the lines at the bottom +but before hindenburg is executed: + +``` +cd /mnt/onboard/.adds/plato # or whereever Plato is +PLATO_STANDALONE=1 ./plato.sh +``` + +You would probably also want to remove the lines where Nickel-specific +programs/scripts are running like nickel, hindenburg, pickel, sickel, +etc. + +Now on subsequent boots, Plato should automatically have been loaded. +Boot times may also be slightly faster! :D + +## Installing KSM 09 (not doing anymore) +First you would want to [download the Clara HD version of KSM 09](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=166556&d=1538176531) and +[the fix for v4.25](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=184756&d=1610745905). Then, you would want to unzip the KoboRoot.tgz +with separate filenames so they don't replace each other and we would +untar those into the same directory. After that, we would cd into the +directory and tar it's contents into a new KoboRoot.tgz and place it in +/path/to/kobo/mount/.kobo/. + +An example of what I did after downloading and unzipping the files are +below: + +``` +mkdir koboroot +tar -xvf KoboRoot-main.tgz -C koboroot +tar -xvf KoboRoot-v4.25-darkmodefix.tgz -C koboroot +cd koboroot +tar -czvf ../KoboRoot.tgz . +cd .. +rm -r koboroot +``` + +After your Kobo untars it and you wait a while, you should be presented +with KSM's main screen :D ksm09's main screen running on the kobo clara +hd + +## Auto-Boot into Plato instead of Nickel via KSM (not doing anymore) +First make sure USB support is enabled in KSM and then mount your Kobo +to your computer. Once mounted, go to +/path/to/kobo/mount/.adds/kbmenu_user/confoptions and edit +ksm_ini_options.txt in your favourite editor. You should see many +options that are listed but the one that we're interested in is +ksmAutoselectoption which may have start_nickel and start_koreader +already and what we want to do is add ksmAutoselectoption=start_plato. +After a quick restart to reload the options file, you should be able to +see the new option in KSM's settings under [general] and add item if it +wasn't already added. Now Plato should auto-boot on subsequent +powerons. diff --git a/posts/st-bitmap-font-fix.md b/posts/st-bitmap-font-fix.md @@ -0,0 +1,35 @@ +title: Fixing bitmap font fallbacks in the st terminal +date: 2023-11-24 12:00 +--- +tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) + +For some context, I have been using xterm for a long while when I'm on OpenBSD +since it is included by default in Xenocara with Terminus as my default font, +and the main reason why I did not use st again was that my bitmap fallback font +for CJK was not loading. Instead, I get an ugly sans-serif scaled font that +looked very out of place in my otherwise clean and crisp bitmap terminal. + +Yes, I did make sure that the font2 patch for st was applied correctly. + +The X11 font string for reference is Fixed: +-misc-fixed-medium-r-normal-ja-18-120-100-100-c-180-iso10646-1 + +It also didn't help that fontconfig was unable to find the font either no +matter how much I looked for it with fc-list and fc-match. The weirder thing is +that when I installed GNU Unifont to my fonts directory, fontconfig was able to +find it and st loaded it (I put a printf in the xloadfonts() function in x.c), +but the same old ugly scaled font was still being shown for CJK. The weirderer +thing was that Unifont was rendering just fine when being used as the main font +instead of in font2. + +I thought to myself why this was happening and wasn't able to find out, until I +reread the font loading portion in x.c's xloadsparefonts() function that came +part of the font2 patch. + +It had set the FC_SCALABLE boolean to 1 (true). That explained why the fallback +font rendered fine as the main font and not fallback. Setting that boolean to +0 (false) fixed my fallback font not matching issue, and now I have clean and +crisp looking text that I can read more easily. + +I already disliked fontconfig, freetype, xft, and friends (don't get me started +on pango and harfbuzz), but this incident made me dislike it further. diff --git a/posts/tmpfilehost.md b/posts/tmpfilehost.md @@ -0,0 +1,71 @@ +title: Creating a Temporary File Hoster +date: 2022-04-27 12:00 +--- +For the past couple years, whenever I wanted to upload a file, I would +curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh). + +Since I want to selfhost, I thought i can just use either of what those +three used. Earlier today though, I realized I could just copy the +file(s) I want to upload via rsync/scp to a public directory that gets +served by an httpd or gopherd. + +From what I understand, the previous file hosters had a program running +that read the file that the user uploads to them, does some renaming, +and writes that to a directory that is served. After some time, that +file is deleted. The first part can be handled via rsync/scp like +mentioned previously. For automatic deletion, I recently saw in find's +man page that it can list that haven't been modified via the -mtime +flag, so that can be used with a cron job. + +But while thinking of this idea, I got stumped by how to print back the +url to this file that is uploaded since printing the filename as is +appended to its baseurl, there could be spaces and other invalid +unescaped characters which programs trying to download it may not like. + +I thought I could just create a separate program for this. However, +doing this seemed more complicated than just copying the file to the +server. So, with the help of awk and some StackExchanging, I've been +able to do it. + +`upfile.sh`: +```sh +#!/bin/sh +urlencode() { + awk ' +BEGIN { for (i = 1; i < 256; i++) hex[sprintf("%c", i)] = sprintf("%%%02X", i) } +{ + for (i = 1; i <= length($0); i++) { + c = substr($0, i, 1) + printf("%s", c ~ /^[-._~0-9a-zA-Z]$/ ? c : hex[c]) + } + printf "\n" +} +' +} + +FILE="$1" +SERVER="REPLACEME" +BASEURL="https://u.$SERVER" + +[ -z "$1" ] && exit 1 + +scp "$FILE" "$SERVER":files/ || exit 1 +printf "%s/" "$BASEURL" +basename "$FILE" | urlencode +``` + +Then to purge these files after they become too old (e.g. 3 days), you +can put something like this in a cron job to run daily (replace file +directory): + +``` +0 0 * * * find /path/to/dir/ -mtime +3 -exec rm {} \; +``` + +You can also put this command in /etc/daily.local or /etc/cron/daily, +or whatever file your root crontab's @daily runs (if there is one). + +And that's it! The only difficult part that I experienced was encoding +the name of the file and originally did that in C. However, having a +mixed C and shell program just for file uploading didn't sit right with +me. It seems like whenever you're in doubt, you can rely on awk huh. diff --git a/posts/vfio-win10.md b/posts/vfio-win10.md @@ -0,0 +1,316 @@ +title: VFIO Install Notes +date: 2020-10-17 12:00 +--- +You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge. + +# Prerequisites +## UEFI Options +Enable VT-d and VT-x (or AMD equivalent) + +## Kernel Config +Enable KVM and VFIO +> you can set VFIO as builtin but as a module is more flexible +Also add `"iommu=pt intel_iommu=on"` to your kernel command line (or in CONFIG\_CMDLINE) + +### Current Options +``` +... +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y +# use the respective AMD options if using an AMD CPU +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y + +CONFIG_KVM_VFIO=y +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_VGA=y +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +CONFIG_VFIO_MDEV=m +CONFIG_VFIO_MDEV_DEVICE=m +... +``` + +## Packages Required +``` +app-emulation/qemu (actual program) +sys-firmware/edk2-ovmf (UEFI firmware for Nvidia GPU) +media-sound/scream (audio) +looking-glass-client (compile from source if no package, or make your own) +``` + +`app-emulation/libvirt` can be used as well for easier configuration and autostart +but I have had problems with it: +- Service not starting properly, workaround is restarting service after it starts (Gentoo) +- Networks and domains not autostarting, workaround is starting them manually (CRUX) + +### Gentoo USE Flags +``` +app-emulation/qemu gtk opengl sdl sdl-image usb # (spice, ssh, vhost-user-fs, virgl, and virtfs are optional I think) +media-libs/libsdl2 X gles opengl # for Looking Glass +``` +note to self (2020-10-17): check how minimal you can make qemu to run vfio + +# IOMMU +Run `dmesg | grep -E 'DMAR'` and see if `DMAR: IOMMU enabled` or something similar is in output + +# QEMU Script +All code blocks in this section go in the qemu script file unless specified otherwise + +## Environment Variables +```sh +IMG=/path/to/windows-image-file +VIRTIO=/path/to/virtio-iso +WINDOWS=/path/to/windows-install-iso +OVMF=/usr/share/edk2-ovmf/OVMF_CODE.fd +RAM=16G +ULIMIT=$(ulimit -l) +ULIMIT_TARGET=$(( $(echo $RAM | tr -d 'G')*1048576+100000 )) + +GPU_VIDEO=01:00.0 +GPU_AUDIO=01:00.1 +VIDEOID="10de 13c0" +AUDIOID="10de 0fbb" +VIDEOBUSID="0000:${GPU_VIDEO}" +AUDIOBUSID="0000:${GPU_AUDIO}" +``` + +## VFIO Detaching and Attaching +```sh +vfio_on() { + # for nvidia card with proprietary drivers + rmmod nvidia_drm + rmmod nvidia_modeset + rmmod nvidia + + # disable bumblebee service or use bbswitch to detach card if using bumblebee + + modprobe vfio-pci + + echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/new_id + echo $VIDEOBUSID > /sys/bus/pci/devices/$VIDEOBUSID/driver/unbind + echo $VIDEOBUSID > /sys/bus/pci/drivers/vfio-pci/bind + echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/remove_id + + echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/new_id + echo $AUDIOBUSID > /sys/bus/pci/devices/$AUDIOBUSID/driver/unbind + echo $AUDIOBUSID > /sys/bus/pci/drivers/vfio-pci/bind + echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/remove_id + + # add rest of gpu devices if they are in the same group (I think 4 devices in 1000 or 2000 series nvidia) +} + +vfio_off() { + rmmod vfio_iommu_type1 + rmmod vfio_pci + rmmod vfio_virqfd + rmmod vfio + + modprobe nvidia +} +``` + +## Networking +```sh +net_on() { + ip tuntap add dev tap0 mode tap group kvm + ip link set dev tap0 up promisc on + ip addr add 0.0.0.0 dev tap0 + + ip link add br0 type bridge + ip link set br0 up + ip link set tap0 master br0 + echo 0 > /sys/class/net/br0/bridge/stp_state + ip addr add 192.168.123.1/24 dev br0 + + sysctl net.ipv4.conf.tap0.proxy_arp=1 > /dev/null + sysctl net.ipv4.conf.enp0s31f6.proxy_arp=1 > /dev/null + sysctl net.ipv4.ip_forward=1 > /dev/null + + iptables -t nat -A POSTROUTING -o enp0s31f6 -j MASQUERADE > /dev/null + iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null + iptables -A FORWARD -i br0 -o enp0s31f6 -j ACCEPT > /dev/null +} + +net_off() { + sysctl net.ipv4.conf.tap0.proxy_arp=0 > /dev/null + sysctl net.ipv4.conf.enp0s31f6.proxy_arp=0 > /dev/null + sysctl net.ipv4.ip_forward=0 > /dev/null + + ip link set dev br0 down + ip link del br0 + + ip link set dev tap0 down + ip tuntap del mode tap name tap0 +} +``` + +Also add this to /etc/conf.d/net if using Gentoo ([source](https://wiki.gentoo.org/wiki/QEMU/Options#Network_bridge)) +> replace `enp0s31f6` with the host/master interface +```sh +... +tuntap_tap0="tap" +config_tap0="null" +bridge_br0="enp0s31f6 tap0" + +config_br0="192.168.123.2 netmask 255.255.255.0" +routes_br0="default via 192.168.123.1" +bridge_forward_delay_br0=0 +bridge_hello_time_br0=10 + +depend_br0() { + need net.enp0s31f6 + need net.tap0 +} +... +``` + +## Hugepages +```sh +hugepages_on() { + PAGES=$(( $(echo $RAM | tr -d 'G') * 1048576 / 2048)) + mkdir -p /dev/hugepages + mount -t hugetlbfs hugetlbfs /dev/hugepages + echo $PAGES > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages +} + +hugepages_off() { + echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages + umount /dev/hugepages +} +``` + +## QEMU Command +### Before installing guest OS (Windows 10 used as example) +```sh +ulimit -l $ULIMIT_TARGET + +qemu-system-x86_64 \ + -name 'vfio-vm' \ + -vga qxl \ + -nodefaults -enable-kvm -machine q35 \ + -m $RAM -mem-path /dev/hugepages \ + -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ + -smp 8,sockets=1,cores=4,threads=2 \ + -rtc clock=host,base=localtime \ + -boot menu=on -boot d \ + -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ + -drive if=pflash,format=raw,readonly,file=$OVMF \ + -drive file="$VIRTIO",id=cd1,media=cdrom \ + -drive file="$WINDOWS",id=cd2,media=cdrom \ + -device virtio-scsi-pci,id=scsi0 \ + -device scsi-hd,bus=scsi0.0,drive=rootfs \ + -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none + +ulimit -l $ULIMIT +``` +### After installing guest OS +```sh +ulimit -l $ULIMIT_TARGET + +qemu-system-x86_64 \ + -name 'vfio-vm' \ + -vga none -nographic \ + -nodefaults -enable-kvm -machine q35 \ + -m $RAM -mem-path /dev/hugepages \ + -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ + -smp 8,sockets=1,cores=4,threads=2 \ + -rtc clock=host,base=localtime \ + -boot menu=on -boot c \ + -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ + -device vfio-pci,host=$GPU_VIDEO,multifunction=on,x-vga=on \ + -device vfio-pci,host=$GPU_AUDIO \ + -device ivshmem-plain,memdev=ivshmem,bus=pcie.0 \ + -object memory-backend-file,id=ivshmem,share=on,mem-path=/dev/shm/looking-glass,size=32M \ + -device virtio-keyboard-pci \ + -device virtio-mouse-pci \ + -object input-linux,id=kbd0,evdev=/dev/input/by-id/usb-Corsair_Corsair_K70R_Gaming_Keyboard-if02-event-kbd,grab_all=on,repeat=on \ + -object input-linux,id=mouse0,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-event-mouse \ + -object input-linux,id=mouse1,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-if01-event-kbd,grab_all=on,repeat=on \ + -drive if=pflash,format=raw,readonly,file=$OVMF \ + -drive file="$VIRTIO",id=cd1,media=cdrom \ + -device virtio-scsi-pci,id=scsi0 \ + -device scsi-hd,bus=scsi0.0,drive=rootfs \ + -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none + +ulimit -l $ULIMIT +``` + +# Extra +## Adding USB Devices +Get vendor and product id from `lsusb` and add them to your QEMU command arguments: +```sh + -device qemu-xhci,id=xhci0 -device usb-host,bus=xhci0.0,vendorid=0x<yourvendorid>,productid=0x<yourproductid> +``` +Example for my USB bluetooth receiver: +``` +$ lsusb +... +Bus 001 Device 004: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth +... +``` +My vendorid is `0x0b05` and productid is `0x17cb`, so in QEMU it would be: +```sh + -device qemu-xhci,id=<usb-bus-id> -device usb-host,bus=<usb-bus-id>.0,vendorid=0x0b05,productid=0x17cb +``` + +## Set CPU Affinity +While libvirt makes this more simple, it appears we need a script/function to do it in bare QEMU +Borrowed from [here](https://null-src.com/posts/qemu-optimization/post.php#taskset) +> note: uses bash-isms so that's why I put it in a separate file +```bash +#!/bin/bash +THREAD_LIST="0,4,1,5,2,6,3,7" +NAME="vfio-vm" + +sleep 20 && +HOST_THREAD=0 +# for each vCPU thread PID +for PID in $(pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | awk -F',' '{print $2}' | awk '{print $1}') | grep CPU | pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | cut -d',' -f2 | cut -d' ' -f1) | grep CPU | sort | awk -F',' '{print $2}') +do + let HOST_THREAD+=1 + # set each vCPU thread PID to next host CPU thread in THREAD_LIST + echo "taskset -pc $(echo $THREAD_LIST | cut -d',' -f$HOST_THREAD) $PID" | sh +done +``` + +## Additional Disk +You can add another disk by simply copying the arguments for adding the rootfs and slightly modifying +Example for a qcow2 image: +``` + -device virtio-scsi-pci,id=<scsi-id> \ + -device scsi-hd,bus=<scsi-id>.0,drive=<drive-id> \ + -drive file=<location>,id=<drive-id>,index=0,format=qcow2,media=disk,if=none +``` + +## No Drives During Installation +Make sure virtio driver is loaded: +- Click Load Driver +- Choose virtio-cd disc > amd64 > w10 and press enter +- Load Red Hat Virtio SCSI driver + +## Looking Glass Not Starting +Make sure no virtual display like QXL is loaded too (`-nographic -vga none` in QEMU) + +## JACK Support +To use JACK instead of Scream, you can use these QEMU arguments +```sh +-audiodev jack,id=snd0,in.client-name=default,out.client-name=default,in.start-server=off,out.start-server=off,in.exact-name=on,out.exact-name=on,in.connect-ports=system,out.connect-ports=system,in.frequency=48000,out.frequency=48000,timer-period=2048,out.buffer-length=5120 \ +-device ich9-intel-hda \ +-device hda-output,audiodev=snd0 \ +``` +You might need to change the timer-period and buffer-length if experiencing crackling. +Also you might have to change the controller (ich9-intel-hda) and codec (hda-output) to something else. + +To list controller and codecs, run: +```sh +qemu-system-x86_64 -device help | grep hda +``` diff --git a/posts/workflow_9years.md b/posts/workflow_9years.md @@ -0,0 +1,231 @@ +title: *nix workflow after nearly a decade (raw braindump) +date: 2026-04-13 12:00 +--- + +I was asked a few times from members of my university's cybersecurity +club (I was a former e-board member and it's my main club) over the +past months of how I use a computer since apparently how I use it is +different from how others do it. They also found it fascinating that I +used Linux/*BSD for as long as I did, and I'm probably among very few +others if any at my university that used it for like 9.5 years. It's +organized in what got me into this in the first place, my OS-hopping, +my editor-hopping, what my current workflow is, and my (maybe lack of +meaningful) thought process behind each switch. The TL;DR of that is +I'm like a purist (primarily with the UNIX philosophy) and minimalist +(reducing "bloat" as much as possible) and that guided a lot of my +decisions up till now at the end of college. Any mistakes I made or +any "cringe" I did like being a 4chan `/g/` kid can be blamed on me +being 12/13 at the time. The following is the raw braindump before I +condensed it into point form. + +--- + +I was introduced to Linux via Luke Smith's early video on why use +terminal programs. Then by watching his other videos, I got introduced +to stuff like different kinds of distros (he used Parabola at the time +and Parabola's wiki in 2017 hadn't removed the beginners guide page +unlike Arch wiki, though in hindsight they're basically the same), +tiling window managers (i3, dwm), suckless movement and minimalism +(was the start of me obsessing over purism even to my detriment +sometimes as in spending too much time that I miss deadlines), using +LaTeX for documents and presentations, etc. This was during his early +days back in 2017 and 2018, before he quit being a linguist professor +in Georgia and moved to a cabin in Florida and now complains about les +youths. I didn't watch other Linux-related channels until more +recently with David Wilson's System Crafters for Emacs and Guix (more +on this at the very end, it's a recent change that fundamentally +changed how I do stuff, this will come up a lot). + +This put me on the path of both distro-hopping and +WM-hopping. Reminder that I started this journey when I was 12 +(now 21) so I had lots of time on my hands. I started with Parabola +and then switched to Arch shortly after for wifi drivers, then setup +Gentoo through reading its handbook to learn about Linux more, and +then later did a full LFS+BLFS twice, then CRUX, Sabotage, KISS, +Alpine, and then switched between them depending on what little thing +annoyed me at the time. Of these, CRUX really made me feel at "home" +with giving me just enough packages for a minimal base and I liked +being a package maintainer for a short while. I found CRUX through +z3bra on the nixers.net forum talking about the differences between it +and Gentoo. Sabotage (the way it did stuff was unique and interesting +to me at the time but only used for one hop) and KISS (what I wished +CRUX was but because it didn't have the drunk tux mascot I didn't use +it much beyond a couple hops) from people on IRC and XMPP. I learned a +lot about system administration and writing my own packages through +distro-hopping. Eventually, the choices converged to Arch (if I wanted +something easy), CRUX (because it made me feel fuzzy inside), Gentoo +(USE flags put me further on the path of purism, not as much need to +maintain so many packages in my overlay unlike CRUX). I later also +found out about the BSDs in my goal of more minimalism and purism. It +being direct descendants of the venerable Bell Labs's Research +UNIX. FreeBSD was what I wished Linux was and I liked its better +documentation and integrated first-class ZFS support. OpenBSD I loved +for its documentation, focus on security above all else, tight-knit +and knowledgeable mature community (unlike with most of Linux), +package management feeling more similar to CRUX, mascot, and being +Canadian (patriotism I guess). Among the OSes I used the longest +without hopping, CRUX, Gentoo, and OpenBSD are the ones I really +used. I usually switched away from CRUX due to power user burnout from +maintaining packages for adding and making them more minimal, same +from Gentoo but to lesser extent due to many other overlays, and from +OpenBSD for Windows virtualization at the time and gaming (though I +did find out more about FOSS engines and did more retro emulation +under OpenBSD). I also had a phase in high school grade 12 with +plan9/9front. Really loved the simplicity and elegance of it. Its +windowing manager rio/8.5 and acme editor also showed me that mice +aren't an inherently bad thing for computer use when designed +properly. I couldn't go further with dailying it because my i219-v and +r8168 driver wasn't working properly even after I tried patching it +with my then meager C skills. Later in college around junior year, I +was peer pressured into NixOS from my functional programming +friends. I liked the idea behind it and it made systemd somewhat +usable, but I disliked the special snowflake DSL (they should have +used something else as a base like Haskell or anything else they took +inspiration from) and it liked pulling in all sorts of transient +dependencies, the exact opposite of what I wanted in Linux since I +started using it years ago. What really put me off more than transient +deps was poor and inconsistent documentation (like pretty much nothing +about flakes: there was a disconnect in documentation of what the +broader community used and what upstream deemed stable). But, it had +advantages like helping organize my system+home configs and dotfiles +all in one place which was very nice. So I briefly tried Guix, but +once again without knowing its language was hard to use and also +trying to mould my existing suckless+vi non-emacs worklow into it was +hard at the time. So I once again switched back and forth between +Arch, CRUX, Gentoo, and NixOS despite their shortcomings I detailed +earlier: my power user burnout or getting bored. Continuing later for +recent switch to Guix+Emacs. + +So now about window manager choice. I started with i3 since that's +what Luke Smith used and I was curious about how a keyboard-only +workflow would look like. It's also what the most popular WM on +r/unixporn was. Back in the day when pretty much every post there was +either a close-to-default i3-gaps setup or bspwm instead of sway and +hyprland now. I then switched to bspwm because it was more minimal and +UNIX philosophy like where it split keybind handling into separate +program sxhkd. I also used herbstluftwm, the manual tiling was +nice. Then comes dwm, my main WM of choice for a long time since it +blended minimalism with functionality and also by suckless so was +elegant. However, I still did end up switching to spectrwm since it +looked similar visually but I found it easier to config. According to +my screenshots though, that didn't last for long. I think I only +stayed on it for a few months before switching back to dwm. I did +briefly try out sway to see if Wayland was really all that great, but +ultimately switched back to dwm again, and only really used it when I +felt too lazy to setup Xorg on a new system and not using my +pre-existing configs. Again, continuing later for my recent switch to +Guix+Emacs. + +Missing what editor I used is criminal for this kind of topic. Going +back to before Linux, I used Eclipse for Java and Notepad++ for +regular stuff, and then I think I used Atom for a brief period of time +(VS Code wasn't out yet or something in 2016/17). I didn't do much +programming back then, partly because getting dependencies and +compiling anything is a pain if my experience with compiling aseprite +(sprite editor with cmake buildsystem) was anything to go off of. When +I started using Linux, I also started with Vim. Programs like it were +what got me to switch in the first place. Turns out learning your +tools is important (and that comes up a lot). Even back then I didn't +like using much of the pre-made configs, they were bloated and harder +to reason about as a new user since defaults were changed. Also had a +brief stint with Emacs, but not knowing basic Lisp made it hard to +"know" it and it was bloated (common joke is it's an operating system +that lacks a good editor) and also not optimized on Windows (same +config from Linux) where it was just noticeably more sluggish on muh +gamin' laptop when running Win10 instead of like Arch or Gentoo. After +learning Vim enough like how to move easily and basic ex commands, I +of course wanted more minimalism. Had a nice time with vis and nvi, +used them for a while. In my plan9 phase, I used acme briefly and +learned a lot about sam through its manual, which also taught me how +to use ed the standard text editor, which also taught me (basic) regex +which I can't overstate how much better it made editing files in +addition to vi motions. + +Finally, my current workflow and choices. It's now all based around +Lisp and Scheme because they make me feel all fuzzy inside when +learning it, just like I did when learning to use Linux in middle +school and how to program in C. The propaganda that got me into using +this now was when I heard about the Lispy Gopher Show when I was +briefly on the Fediverse through Prahou (the author/artist of +unix_surrealism from analog_nowhere). While I did briefly use Emacs in +the past, I did not learn it properly. As in, not knowing Lisp meant I +needed to look a lot of things up instead of just writing them +myself. Technically with the vi-like editors, I also didn't write +scripts in them nor needed to touch their config due to how minimal +they already were by default and that regex+vi-motions going a long +way and there being packages to bridge the remaining gap for +integrations. But with Emacs, the parentheses I guess made it more +daunting or something. This sort of mirrors what I did when I first +got into Linux (well Arch) as I read a lot through its wiki. But +compared to just regular system administration where you run a bunch +of commands or even making your own distro via LFS, I guess properly +learning an editor and its programming language was too much for me at +the time. For new Emacs users, it was also recommended a lot that they +use a pre-made opinionated config like Doom-Emacs or Spacemacs (neovim +has a similar situation) and that really put me off since that felt +like I would be learning instead how those work instead of the editor +itself. Now that I know some functional programming through OCaml and +to some extent Nix from a couple summers ago, learning Lisp and Scheme +was actually much easier. Compared to using a vi-like editor, using +Emacs seemed nicer for working with these kinds of languages since I +can selectively execute parts of a program, simliar to something like +Jupyter notebook without it being so web- and Python-focused and being +an inefficient use of system resources. The main reason why I did not +want to use Emacs previously was that it seemed like a monolithic +kitchen sink of everything. I think it being described as an operating +system within an operating system isn't too much of an inaccurate +description. However, compared to Linux and Xorg proper where I tried +following minimalism and the UNIX philosophy as much as I could +(i.e. small, minimal, self-contained programs for a specific task), +there was not much cohesion between them. At most, they'll have +vi-keybinds and happen to use ncurses but the layout of everything +looks different and configured with different syntaxes (e.g. mutt the +mail client looks different from newsboat the RSS reader and different +from lynx and links2). Meanwhile with Emacs, yes there are multiple +packages and yes I'm not necessarily using POSIX shell scripts for +connecting things together, but Lisp is a more powerful language than +something like shell that depends on other programs (written in other +languages) to do even simple stuff. With Emacs, I now have everything +integrated into a single program, everything properly goes through +text-based buffers, and as a result is even easier to integrate around +because everything is primarily text. Also previously, some popular +packages that people use also seemed like it may have contributed to +Emacs's bloat in my point of view at that time like /needing/ +something like ivy or helm. There's better packages available that do +the same thing now, like orderless (for fuzzy searching) combined with +vertico (for the vertical complete menu that ivy gave), and consult +for better autocomplete for various existing Emacs functions, among +other stuff. Now it's my main editor since like last summerish, and I +configured it to be my editor, Scheme programming via Geiser, Lisp via +just Emacs (since for now I'm mainly using Emacs Lisp and not Common +Lisp+SLIME) and using the eval-* functions a lot (for both Lisp and +Scheme), document editing and task planning and habit tracking through +org-mode (some people use Emacs just for org-mode since it's much more +than just a markup language), email through notmuch+mbsync+msmtp +(stayed pretty much the same except I'm using notmuch.el directly +instead of through like mutt or aerc), RSS through elfeed, browsing +primarily through eww (though I have to use qutebrowser for js-heavy +sites like Canvas), document viewing through pdftools and docview +instead of through mupdf (though for some larger PDFs like textbooks, +mupdf is just faster but not needed for most of my PDFs), backgrounded +programs through dtach and its associated emacs management package +instead of tmux, gptel for interacting with my local LLMs running on +my desktop through vllm, and finally as my X window manager via EXWM +instead of dwm or any other WM I used to use in the past. Works well +when playing games too like Elite Dangerous, Emacs doesn't get in the +way. + +I know this was very ramble-y. I just braindumped since there's so +much to cover and a lot of stuff to remember over the past 9 years +that I couldn't think in a more organized way without having all of it +written down. I probably missed some stuff, so any questions? + +--- + +In the actual presentation, I missed mentioning my peripherals (a +Ferris Sweep with Kailh Choc Ambient Nocturnal switches for laptop, +Corne with Zealios Zilent v2 switches for my desktop, and a Ploopy +Adept as my mouse for both) as well since that's also different from +how most people use it, as well as my current project "X380", a modded +stripped-down X280 (I'll make a post when it's more finalized after +fixing my 3D printer). diff --git a/static/agpl-3.0.txt b/static/agpl-3.0.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<https://www.gnu.org/licenses/>. diff --git a/static/bsd_license.txt b/static/bsd_license.txt @@ -1,24 +0,0 @@ -BSD 2-Clause License - -Copyright (c) 2024, Vineet Kumar - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/static/cc-by-4.0.txt b/static/cc-by-4.0.txt @@ -1,395 +0,0 @@ -Attribution 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution 4.0 International Public License ("Public License"). To the -extent this Public License may be interpreted as a contract, You are -granted the Licensed Rights in consideration of Your acceptance of -these terms and conditions, and the Licensor grants You such rights in -consideration of benefits the Licensor receives from making the -Licensed Material available under these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/static/cc-by-nc-sa-4.0.txt b/static/cc-by-nc-sa-4.0.txt @@ -0,0 +1,438 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/static/main.css b/static/main.css @@ -0,0 +1,203 @@ +/* fonts */ +@font-face { + font-family: "Comic Mono"; + font-weight: normal; + font-style: normal; + font-display: swap; + src: url('https://dtinth.github.io/comic-mono-font/ComicMono.ttf'); +} + +@font-face { + font-family: "Comic Mono"; + font-weight: bold; + font-style: normal; + font-display: swap; + src: url('https://dtinth.github.io/comic-mono-font/ComicMono-Bold.ttf'); +} + +@font-face { + font-family: 'Comic Neue'; + src: local('Comic Neue Italic'), local('ComicNeue-Italic'), + url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Italic.woff2') format('woff2'); + font-weight: normal; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Comic Neue'; + src: local('Comic Neue Bold'), local('ComicNeue-Bold'), + url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Bold.woff2') format('woff2'); + font-weight: bold; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Comic Neue'; + src: local('Comic Neue Bold Italic'), local('ComicNeue-BoldItalic'), + url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-BoldItalic.woff2') format('woff2'); + font-weight: bold; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Comic Neue'; + src: local('Comic Neue Regular'), local('ComicNeue-Regular'), + url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Regular.woff2') format('woff2'); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +/* main */ + +:root { + /* kaolin valley light */ + --background: #faf2e9; + --brbackground: #ebd7be; + --foreground: #5e5854; + --brforeground: #6b6560; + --border: #f0dfca; + + --black: #5e5854; + --brblack: #544b44; + --red: #d42215; + --green: #0d7a75; + --yellow: #d1832e; + --blue: #526af3; + --magenta: #cf44ac; + --cyan: #0bc9cf; + --white: #ebd7be; +} + +@media (prefers-color-scheme: dark) { + :root { + /* kaolin valley dark */ + --background: #1c1616; + --brbackground: #5e5854; + --foreground: #eee6d3; + --brforeground: #c7c2af; + --border: #2e2a29; + + --black: #28211e; + --brblack: #544b44; + --red: #e84c58; + --green: #91f368; + --yellow: #eed891; + --blue: #41b0f3; + --magenta: #cea2ca; + --cyan: #6bd9db; + --white: #eee6d3; + } +} + +html { + color: var(--foreground); + background-color: var(--background); +} + +nav { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +nav ul { + display: flex; + list-style: none; + margin: 0; + padding: 0; + gap: 1rem; +} + +body { + max-width: 720px; + margin: 0 auto; + padding: 1rem; + font-family: "Comic Neue", "Comic Sans MS", sans-serif; +} + +h2 { + margin-bottom: 0; +} + +a { + color: var(--yellow); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:visited { + color: var(--green); +} + +article { + margin: 0 auto; + line-height: 1.3; +} + +article img { + display: block !important; + margin: 0 auto !important; + max-width: 90%; +} + +@media (max-width: 640px) { + article img { + max-width: calc(100% - 2rem); + } +} + +footer { + margin-top: 2rem; + text-align: center; + font-size: 0.8rem; + color: var(--brblack); +} + +pre { + background-color: var(--brbackground); + padding: 0.25rem 1rem; + margin: 0 -1rem; + max-width: 100%; + overflow-x: auto; +} + +pre, code { + font-family: "Comic Code", "Comic Mono", monospace; +} + +summary { + cursor: pointer; + background-color: var(--brbackground); + padding: 0.25rem 1rem; + margin: 0 -1rem; +} + +details[open] { + border-bottom: 1rem solid var(--border); + margin: 0 -1rem 1rem; + padding: 0 1rem; +} + +blockquote { + border-left: 5px solid var(--border); + background-color: var(--brbackground); + padding: 0 1rem; + margin-left: calc(-1rem - 5px); + margin-right: -1rem; +} + +.text-center { + text-align: center; +} + +.date { + font-family: "Comic Code", "Comic Mono", monospace; +} diff --git a/theme.scm b/theme.scm @@ -0,0 +1,73 @@ +(define-module (theme) + #:use-module (haunt artifact) + #:use-module (haunt asset) + #:use-module (haunt builder blog) + #:use-module (haunt html) + #:use-module (haunt post) + #:use-module (haunt site) + #:use-module (srfi srfi-19) + #:export (vin-theme)) + +(define (link name uri) + `(a (@ (href ,uri)) ,name)) + +(define vin-theme + (theme #:name "vin" + #:layout + (lambda (site title body) + `((doctype "html") + (head + (meta (@ (charset "utf-8"))) + (meta (@ (name "viewport") + (content "width=device-width, initial-scale=1"))) + (title ,(string-append title " - " (site-title site))) + (link (@ (rel "alternate") + (type "application/atom+xml") + (title "Atom feed") + (href "/feed.xml"))) + (link (@ (rel "icon") + (type "image/png") + (href "/static/AT_terminus.png"))) + (link (@ (rel "stylesheet") + (type "text/css") + (href "/static/main.css"))) + (body + (div (@ (class "container")) + (nav + (ul (li ,(link "Vineet K" "/"))) + (ul (li ,(link "About Me" "/about.html")) + (li ,(link "Blog" "/index.html")) + ;; (li ,(link "Projects" "/projects.html")) + )) + ,body + (footer (@ (class "text-center")) + (p "The content for the site is under the " ,(link "CC-BY-NC-SA-4.0 License" "/static/cc-by-nc-sa-4.0.txt") ". " + "The code for this site is under the " ,(link "GNU AGPLv3 License" "/static/agpl-3.0.txt") "."))))))) + #:post-template + (lambda (post) + `((article + (h1 (@ (class "title")) + ,(post-ref post 'title)) + (div (@ (class "date")) + ,(date->string (post-date post) + "~B ~d, ~Y")) + (div (@ (class "post")) + ,(post-sxml post))))) + #:collection-template + (lambda (site title posts prefix) + (define (post-uri post) + (string-append prefix "/" (site-post-slug site post) ".html")) + `((h2 ,title " " + (a (@ (href "/feed.xml")) "(feed)")) + ,(map (lambda (post) + (let ((uri (post-uri post))) + `(div (@ (class "posts")) + (div (@ (class "post")) + (span (span (@ (class "date")) + ,(date->string + (post-date post) + "~Y-~m-~d")) + " - " + (a (@ (href ,uri)) + ,(post-ref post 'title))))))) + posts))))) diff --git a/update.sh b/update.sh @@ -1,4 +0,0 @@ -#!/bin/sh -hugo -#rsync --exclude="update.sh" --delete -ash . vineetk.net:/usr/local/www/vineetk_html/ -rsync --exclude="update.sh" --delete -ash public/ 10.0.13.1:/var/www/vineetk_html/