diff --git a/content/blog/beets-soulseek.md b/content/blog/beets-soulseek.md
index c249a4b..1ef497e 100644
--- a/content/blog/beets-soulseek.md
+++ b/content/blog/beets-soulseek.md
@@ -1,4 +1,5 @@
---
title: Beets and Soulseek Or, How I Learned to Give Up and Love The Hoard
date: 2025-02-03
+draft: true
---
diff --git a/content/blog/hacking-hikmicro-pt1/hacking-hikmicro.md b/content/blog/hacking-hikmicro-pt1/hacking-hikmicro.md
index 27e1c96..80a1fe9 100644
--- a/content/blog/hacking-hikmicro-pt1/hacking-hikmicro.md
+++ b/content/blog/hacking-hikmicro-pt1/hacking-hikmicro.md
@@ -1,14 +1,14 @@
---
title: Reversing an image format
date: 2025-01-15
-tags: reverse-engineering, hacking-hikmicro
+tags: [reverse-engineering, hacking-hikmicro]
+drafts: true
---
This post is the first in a series on reverse engineering binary file formats using an array of tools,
mainly to serve as insight into how to approach these kinds of challenges as they can be daunting.
Part one focuses on the image format.
-
# Introduction
*[ITAR]: International Traffic in Arms Regulations
@@ -17,18 +17,21 @@ These arrays are higher resolution and faster framerates than what can reasonabl
to low competition and ITAR restrictions. Most popular are the low-cost modules by Infiray, which provides whitelabel solutions
to a host of other companies (TOPDON, Vevor, HTI, UNI-T) to relabel and sell under their own name. They come in two major
form factors: Phone add-on and gun-grip unit. Existing work has documented and reverse-engineered the phone communication protocols,
-but
+but
-I've been burned once by the phone-dongle style before with Seek Thermal. Simply put, the pace of smartphones is longer than
-the target lifespan of these products. Therefore I wanted one that could be used in a dedicated fashion. The PC
+I got burned once by the phone-dongle style before with Seek Thermal. Simply put, the pace of smartphones is longer than
+the target lifespan of these products. This time, I wanted one that was standalone. The PC
connectivity was still important to me, since there are certain operations that can only be done with access to raw
data, like Lock-In Thermography.
-For that reason, the Hikmicro line of portable imagers interested me. It's more expensive than the whitelabel Infiray
-products, but offers some pretty nice looking PC software and uses a Radiometric JPEG image format for data.
-Live USB is advertized and it supposedly also delivers radiometry over the USB (!). This is on
-top of being a standalone unit so you don't need to use an odd phone app. However this choice seems less popular on forums
-and there is no reverse engineering project that exists already, so we'll have to start from scratch.
+For that reason, the Hikmicro line of portable imagers interested me. It's more
+expensive than the whitelabel Infiray products, but offers some pretty nice
+looking PC software and uses a Radiometric JPEG image format for data.They
+advertise Live USB video and it supposedly also delivers radiometry over the
+USB (!). This is on top of being a standalone unit so you don't need to use an
+odd phone app. However this choice seems less popular on forums and there is no
+reverse engineering project that exists already, so we'll have to start from
+scratch.
# Getting the picture
diff --git a/content/blog/nix-unprivileged-deployments.md b/content/blog/nix-unprivileged-deployments.md
index 35d6c88..92ec517 100644
--- a/content/blog/nix-unprivileged-deployments.md
+++ b/content/blog/nix-unprivileged-deployments.md
@@ -4,13 +4,16 @@ date: 2025-04-17
tags: NixOS
---
-Note: this post assumes familiarity with the Nix Ecosystem.
+{% callout %}
+This post assumes familiarity with the Nix ecosystem.
+{% endcallout %}
Nix and NixOS make managing servers much easier than bespoke scripts or
complex Ansible playbooks. While I don't think NixOS is ready for
personal computers, it absolutely makes sense on less dynamic devices
like servers or embedded-ish machines.
+
We can use NixOS and nixpkgs to derive a fully defined operating system and services.
Then, we can:
@@ -19,7 +22,7 @@ Then, we can:
- push the new configuration to a remote server using [deploy-rs]()
The latter is interesting. With a bit of setup, we can do GitOps with rollback
-and push-deployments. `deploy-rs` is a glorified `nix copy` with some extra magic
+and push-deployments. `deploy-rs` is like `nix profile` with helper scripts
to "activate" the copied closure. Activation typically means running `home-manager switch`
or switching the NixOS profile.
@@ -37,46 +40,60 @@ And then have `nginx` use `/home/blog/_site/` as the site root. This works, but
Other users have tied their blog to the NixOS system-level configuration, like [this user](https://jeancharles.quillet.org/posts/2023-08-01-Deploying-a-static-website-with-nix.html). While I think this
is a good solution, it has the issue of relying on root access for updating the site.
To me, this feels excessive. I should be able to deploy my site from a lesser-privileged user.
+This method also ties sysadmin-tasks to our blog, which isn't keeping our concerns separate.
# Scaffolding the Solution
Let's recap:
1. Build the site using a nix derivation
-2. Copy the derivation to a server using a locked down non-root account.
-3. Create well-known path that points to the latest version of the site in the nix store.
-4. Configure `nginx` to serve from this well known path.
+2. Configure `nginx` to serve from a well-known path (`/var/lib/site/public`)
+3. Copy the derivation to a server using a locked down non-root account.
+4. Symlink `/var/lib/site/public` to our static site in the nix store.
I'll do it manually to get an idea of how it should work.
## nix build blog
-I build my blog using [11ty](https://www.11ty.dev), and I use `npm run build` to generate
-the static sources. Nix supports building npm-like packages with `buildNpmPackage`, which
-uses a [Fixed-output derivation](https://nix.dev/manual/nix/2.28/store/derivation/outputs/content-address#fixed)
-to store the dependencies of the project. Then, for the `installPhase`, we just copy the built contents
-to `$out`. I need to add `vips` and `pkg-config` as well because 11ty processes my images.
+I build my blog using [11ty](https://www.11ty.dev), and I use `npm run build`
+to generate the static sources. Nix supports building npm-like packages with
+`buildNpmPackage`. This uses a [Fixed-output
+derivation](https://nix.dev/manual/nix/2.28/store/derivation/outputs/content-address#fixed)
+to store the dependencies of the project if it is stored elsewhere, but I found
+a better method that imports the `package.lock` directly. Then, for the
+`installPhase`, we just copy the built contents to `$out`. I need to add `vips`
+and `pkg-config` as well because 11ty processes my images. You should add any
+other tools you'd need to build your site.
The end result looks like this:
```nix
-default = pkgs.buildNpmPackage {
+{
+ nodejs,
+ pkg-config,
+ buildNpmPackage,
+ importNpmLock,
+ vips,
+}: buildNpmPackage {
name = "myblog";
version = "unstable";
- buildInputs = with pkgs; [
+ buildInputs = [
nodejs
vips
];
- nativeBuildInputs = with pkgs; [
+ nativeBuildInputs = [
pkg-config
];
- npmDepsHash = "sha256-Q7rhCjAPPn44DyUZ/uoD+7o4XH33IATfL+v1azEhuW0=";
+ npmDeps = importNpmLock {
+ npmRoot = ./.;
+ };
+ npmConfigHook = importNpmLock.npmConfigHook;
src = ./.;
installPhase = ''
mkdir -p $out/public
- cp -ar _site/ $out/public
+ cp -ar _site/* $out/public/
'';
-};
+}
```
Then, running `nix build` I get my site files in `result/public`, which is what we want.
@@ -109,9 +126,14 @@ module that will set this up:
# TODO: write this
```
+
+Now we have a scoped user, with an ssh key authorized. It needs a shell so we can actually log
+in remotely.
The last step is creating that symlink. This is where the concept of "activation" comes into play.
-For NixOS, `deploy-rs` activation just calls `switch-to-configuration` to make the system change the profile.
-We can effectively do whatever we want here.
+
+
+For NixOS, `deploy-rs` activation just calls `switch-to-configuration` to make
+the system change the profile. We can effectively do whatever we want here.
Reading the [custom activator](https://github.com/serokell/deploy-rs/blob/aa07eb05537d4cd025e2310397a6adcedfe72c76/flake.nix#L58C13-L96C17) source:
```nix
@@ -172,8 +194,9 @@ ln -sn $PROFILE/public /var/lib/static-site/public
Then when deploying with `deploy-rs`:
-```
-error: cannot add path '/nix/store/2sad737aglfzmil72phv0j8s34zzmvzi-myblog' because it lacks a signature by a trusted key
+```bash
+error: cannot add path '/nix/store/2sad737aglfzmil72phv0j8s34zzmvzi-myblog'
+because it lacks a signature by a trusted key
```
Drat. This makes sense though, since it would be a bit dangerous to allow any old user write access to
@@ -182,17 +205,14 @@ the nix store. We have two options:
1. Make `static-site` a trusted user
2. Create a trusted keypair to sign our closure when it's built.
-Pick your poison - the keypair mechanism is slightly more secure.
+Pick your poison - the keypair mechanism is more secure, as it means that
+the `static-site` user can't upload arbitrary packages.
I just want to get this working, so I made `static-site` a trusted user.
Note that if you wanted to use the keypair instead, `deploy-rs` has a
[secret environment variable](https://github.com/serokell/deploy-rs/blob/aa07eb05537d4cd025e2310397a6adcedfe72c76/src/push.rs#L131)
called `LOCAL_KEY` which is a file that contains the signing key.
+Regardless of the outcome you choose, when you re-deploy, it should work properly.
-
-
-
-
-
-
+Let's follow the symlink.
diff --git a/content/blog/zig-is-dark-souls/index.md b/content/blog/zig-is-dark-souls/index.md
index dd888af..3e3adf2 100644
--- a/content/blog/zig-is-dark-souls/index.md
+++ b/content/blog/zig-is-dark-souls/index.md
@@ -1,4 +1,3 @@
-
---
title: Zig is Dark Souls
description: This is both good and bad.
diff --git a/eleventy.config.js b/eleventy.config.js
index 473102d..8345e0d 100644
--- a/eleventy.config.js
+++ b/eleventy.config.js
@@ -145,6 +145,14 @@ export default async function (eleventyConfig) {
//eleventyConfig.addPairedShortcode("section", async (content, transition = "none") => {
// return `