Recent submissions

Comment · 1 year ago
New release of my authentication service written in C. It now offers "multi-reactor" (multiple threads each running their own event loop). In my jmeter tests, it can now support 40,000 req/s fetching the login form and performing login POSTs on my old Xeon E3-1240L v4 (quad-core low-power CPU) which isn't even idle ... of course with everything optional (TLS, request logging, remote host resolving) disabled.

Might be overkill to tune such a simple tool for performance, but I hope to reuse the code eventually for other web services.

Features: Authentication with PAM, a htpasswd-like file with bcrypt hashes, executing some external tool, AND "proof-of-work" crypto challenge (to block malicious bots).

Comment · 1 year ago
TBH, I've shown this before, but a LOT has changed since then, most notably:

* Performance improvements by adding support for epoll() (with singalfd and timerfd), kqueue() and solaris event ports, and also by fixing a few design issues

* Server side sessions are gone, instead signed Json Web Tokens are implemented -> saves lots of RAM

Among other things, swad can do what Anubis can do, that's why it's in the title. It's much smaller though, and proof-of-work-crypto-challenge-to-defeat-bots is just ONE module, the other modules offering more regular means of authentication: by calling some external tool, by checking a bcrypt hash from a file, or by asking PAM.

Contrary to Anubis, it's NOT a reverse proxy but designed to work with nginx' auth_request facility instead, might also work with other reverse proxies if they offer something similar. Swad is written in C, compiles to a 200-300kiB (depending on compiler and platform) binary, needs only zlib, OpenSSL (LibreSSL) and optionally libpam. Doing some stress testing with 1000 distinct simulated clients, I managed to bump up the resident set on my FreeBSD machine to 100MiB, but no more. Without heavy load, it typically stays at much less.

The general architecture of swad is a reactor with attached thread pool. A HTTP request is parsed (to headers and body) in the main thread, then a thread job is created to run the handler pipeline (including response compression, cookie management, form and query string parsing, etc) that's expected to add a HTTP response to some context object, once that's finished, the main thread takes over again sending that out to the client.

During my stress test mentioned above, I was kind of surprised to see the main (reactor) thread almost maxing out one core, while the pool threads (running request pipelines) didn't have too much to do. Well, serving a small login form and processing login requests indeed isn't THAT much work. Maybe it might make sense to have more than one "reactor thread"? Could this work, e.g. by just listening on the same socket from multiple threads?

Comment · 1 year ago
BTW, it also offers authentication with PAM, password files similar to Apache's .htpasswd and by calling some external tool. And it compiles to a (currently) 176kiB binary, which has the default templates, style.css and the javascript for the crypto puzzle built in.

I use it myself on my private server to protect my package build logs (!) from hungry AI bots. WTF...

Comment · 1 year ago
swad is the "Simple Web Authentication Daemon". I just started it and crafted a first release that's still pretty limited in functionality, but does something (IMHO) useful, which I already use myself. More info in the github README.md.

There's a background story. For a few months, I was wondering why most of the time, I couldn't activate my camera in MS Teams meetings (for work) without completely killing my audio ... obviously a bandwidth issue with my upstream that hasn't been there before. Then I stumbled across some article, I think it was ars technica, describing a horrible problem with misbehaving AI bots crawling for data with no limits and no respect (and even trying disguises), causing extreme amounts of traffic and corresponding problems for opensource projects hosting their own infrastructure. Gave me the idea to finally check my nginx logs again. Ok, it was full of bots. The interesting thing is, I don't host any opensource code there. What they downloaded were build logs of my "poudriere" (a package builder for FreeBSD), which can get very large, and I just had them public because there was no reason to hide them ... well until now. WTF do those bots learn from that, uhm, "shit scrolling by"?

So, what to do here? Although I really felt inclined to try one of the nice and naughty tools to poison these bots (IDK, is build logs already some kind of poisoning?), it was clear the pragmatic thing to do is add authentication. Well, you can easily add some HTTP "Basic" auth, but that's far from great. You're typically limited to checking credentials against some "password file", and worse, e.g. Microsoft already decided that "Basic" is "insecure" (oh dear, really? I don't think so as long as you use TLS) and disabled it by default in their "Edge" browser. And chances are you can't change that when using some device you got from your employer.

I did have some old dusty code implementing some very limited HTTP stuff in C lying around that was never published (only used it for experiments with some darknet "hidden services"). I thought it might be fun to implement something. Yep, it was fun. And call me stubborn, but I like doing stuff in plain C, small, efficient, few dependencies. Finally this old HTTP code got some polish and is released as part of something actually useful.

For completeness, I'm well aware I could have taken a very different road. "Just" install some identity provider implementing OIDC. For example keycloak. Well sure, that's awesome stuff. And huge and complex. If you don't have a massively distributed deployment of services and don't intend to ever federate with other organizations, it just felt like using the H bomb to kill a fly.

Comment · 2 years ago
So, let's look at this group of people knowledgeable in programming et al, but not english. Sure, this group exists. It's relatively tiny though. English is the language in any (modern, IOW except where it didn't replace latin yet) science, including CS. The vast majority of other on-topic literature is english. It's hard to learn a decent amount of stuff concerning programming without knowing english.

You can't randomly mix languages in source code, and any other choice of common language than english would exclude a LOT more people from the project.

All of this isn't related to i18n/l10n of your application at all. People not knowing english is a much more relevant factor when talking about user interfaces. I actually plan to localize my Xmoji tool eventually, it's just postponed until more important stuff is done (I mean, I assume most people would get together enough english to be able to use an emoji keyboard after all, but of course, especially seaching would benefit from l10n).

Comment · 2 years ago
For Wayland, keyboard input is "out of scope". (edit: Not entirely, just verified it does forward very basic events, but it's a thing wayland doesn't want to handle, while X11 originally had its own keyboard/mouse/etc drivers) What's typically used is XKB (inherited from X11) with a different backend ([edit: raw events]). So yes, in practice, you'll have the same broken design.

> Also, there seem to be no sane API for managing layouts or switching > them programatically

Layouts only exist as "data" as far as the X server is concerned, clients must fetch them and map themselves from the key codes. Libraries like xkbcommon (or even grandfather Xlib) do the job for you. That said, there are APIs to modify the mapping (by publishing messages/events) as you wish. The ugliness is, apart from the fact that you're forced to fiddle with the mapping at all, that you can't guarantee another client will process everything in sequence. It might apply a new mapping before processing all its queued key press events. That's why my code adds delays between fiddling with the mapping and sending the events.

Yes, it's extremely ugly. Still, at least for me, it works. Try it out ;)

And yes, Windows is doing better here, there's a Unicode-flavor of keyboard events available.

Comment · 2 years ago
> The second worst part is the emoji combining sequences [...]

That was the main reason for me to pull in harfbuzz. At least it "just resolves" those sequences to glyph indices.

Comment · 2 years ago
Thanks for the pointer, this made me have another closer look at xkbcommon's API. Probably not too relevent for the tool I'm currently writing, but I'll keep that in mind: Instead of a key symbol, you can also obtain an utf-8 encoded string. Nice.

Still, in practice, it will only work with some applications...

Comment · 2 years ago
Note input is "out of scope" for wayland and XKB is used there for keyboard input as well. I just had a quick glance at "wtype" source and indeed, it fiddles with the keymap, using xkbcommon. So, assuming a suitable X11 replacement for this "wofi" tool, you could do exactly the same on X11 using "xdotool".
Comment · 2 years ago
Using input methods is the "technically best" solution of course, but it needs configuration and some application support, therefore I wanted something working with "plain X" :)

Sending fake key events is unfortunately "hacky". You need to temporarily switch the keyboard mapping, and many X applications have races between applying a new mapping and processing key press events, that's why I added (now configurable, new release soon) delays... and also, I found applications (e.g. chromium) having issues to correctly combine ZWJ sequences from individual key events, so I added more "hacks" to help with that, also just made configurable.

To sidestep these issues, my tool also offers transfer via "primary selection": Just middle-click an emoji to select it, and middle-click again where you want to insert it. Downside: Two clicks instead of just one.

Comment · 2 years ago
Xcompose only offers sequences started with the "compose" key (whatever it is mapped to) and resulting in a single X key-symbol, so to type an emoji needing multiple uniciode codepoints that way, you'd have to enter multiple "compose sequences". Whatever you describe here is not simple Xcompose. AFAIK, GTK offers entering unicode codepoints in a similar way ...

Of course you can do a lot of things with "input methods" (like popping up some "picker" only when wanted). But then you'll depend on X clients being aware of them in some way, e.g. by implementing the XIM protocol. Lots of applications have that (even xterm), so it might be what you prefer and that's fine. My method with faked key press events is definitely hacky, but will work with any X client, that's the point of it ;)

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton