News for hackers. Stuff that matters.

rraval

Re:Horcrux: Split your file into encrypted fragments on Saturday September 16, 2023 @01:14PM (#37536633)
No mention of libgfshare, which comes with utilities `gfsplit` and `gfcombine`: https://manpages.ubuntu.com/manpages/trusty/man1/gfsplit.1.h...

We use it in production to pregenerate a pool of certificate requests for SSL key pinning. Rotating a key requires m-of-n cooperation.

Re:Memory Safe Languages in Android 13 on Thursday December 01, 2022 @03:05PM (#33821950)
> But ctypes being a terrifying pain in the ass, people tread very carefully around it.

I'm not sure how much people treading carefully actually translates into safety in practice.

CPython in particular has ad-hoc refcounting semantics where references can either be borrowed or stolen and you have to carefully verify both the documentation and implementation of functions you call because it's the wild west and nothing can be trusted: https://docs.python.org/3.9/c-api/intro.html#reference-count...

This ad-hoc borrowed vs stolen references convention bleeds into cffi as well. If you annotate an FFI function as returning `py_object`, cffi assumes that the reference is stolen and thus won't increment the ref count. However, if that same function instead returns a `struct` containing a `py_object`, cffi assumes the reference is borrowed and will increment the ref count instead.

So a harmless looking refactoring that changes a directly returned `py_object` into a composite `struct` containing a `py_object` is now a memory leak.

Memory leaks aren't so bad (even Rust treats them as safe after the leakpocalypse [1] [2]). It's when you go the other way and treat what should have been a borrowed reference as stolen that real bad things happen.

Here's a quick demo that deallocates the `None` singleton:

    Python 3.9.13 (main, May 17 2022, 14:19:07)
    [GCC 11.3.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.getrefcount(None)
    4584
    >>> import ctypes
    >>> ctypes.pythonapi.Py_DecRef.argtypes = [ctypes.py_object]
    >>> for i in range(5000):
    ...     ctypes.pythonapi.Py_DecRef(None)
    ...
    0
    0
    0
    0
    0
    [snip]
    Fatal Python error: none_dealloc: deallocating None
    Python runtime state: initialized

    Current thread 0x00007f28b22b7740 (most recent call first):
      File "<stdin>", line 2 in <module>
    fish: Job 1, 'python3' terminated by signal SIGABRT (Abort)
[1]: https://rust-lang.github.io/rfcs/1066-safe-mem-forget.html [2] https://cglab.ca/~abeinges/blah/everyone-poops/
https://snapdrop.net is my go to for this. Works on any modern browser on the same LAN. Supports files and plain text.

Previous HN discussion: https://news.ycombinator.com/item?id=25524472

Re:Unifying fold left and fold right in Prolog on Friday August 26, 2022 @01:59PM (#32610723)
Hah, you beat me to this by a minute. I guess I'm not the only one that looks back on this paper with fondness.
Re:Unifying fold left and fold right in Prolog on Friday August 26, 2022 @01:58PM (#32610715)
Related: Graham Hutton's classic paper: a tutorial on the universality and expressiveness of fold

[PDF]: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf

Section 5.1 walks the reader through implementing foldl in terms of foldr after laying down the ground work and gradually introducing things one concept at a time.

For me, the eye-opening insight was using foldr to generate intermediate functions as values, which is the sort of thing "functional" programming does without thinking twice, but is mind bending for someone coming from a more traditional procedural language background.

Re:Ask HN: What is your Git commit/push flow? on Thursday March 17, 2022 @02:46PM (#30714538)
> I separate file backup and version control. I keep every git repository I'm working on in Dropbox, and don't ever worry about how often I'm committing and pushing.

Motivated by a slightly different use case (seamless syncing across multiple machines), I built a custom tool that solves this concern within `git`: https://github.com/rraval/git-nomad

You can toss `git nomad sync` into a systemd timer (or cronjob if you prefer) and forget about it.

Re:Ask HN: Best alternatives to Google Analytics in 2021? on Thursday December 23, 2021 @03:45PM (#29666256)
I too wanted to preserve privacy and avoid a cookie banner for my blog. I ended up rolling a privacy preserving proxy via Cloudflare workers that forwards `pageview` events to Google Analytics. It's a single HTML tag to drop in and preserves the navigation and user flow reports on the GA side.

See https://github.com/rraval/zeroindexed/tree/master/packages/t...

The blog explains expanded motivation: https://zeroindexed.com/privacy

Re:Techdirt Is Now Without Any Google Ads or Tracking Code on Wednesday July 28, 2021 @11:18AM (#27984835)
I evaluated both Plausible and Matamo as privacy preserving analytics options for my blog, and ended up rolling my own solution for cost reasons. Cloudflare workers and Pulumi make this pretty trivial to self host.

Here's the Show HN that never picked up steam: https://news.ycombinator.com/item?id=27175347

Re:NixOS 21.05 on Wednesday June 02, 2021 @12:27PM (#27370645)
I was able to make the switch over cold turkey after ~11 years of ArchLinux.

By sheer happenstance, I blogged earlier this week about one particular killer feature that doesn't get enough air time: https://news.ycombinator.com/item?id=27344677

My not-flake-yet configuration can be found at https://github.com/rraval/nix

Re:Nix solves the package manager ejection problem on Monday May 31, 2021 @05:31PM (#27348173)
> How do NixOS users typically manage software that is not a Nix package

By writing a Nix package for it (I don't mean for this to sound flippant, tone is a bit hard to convey over text).

For example I have this alpha quality rust binary that I'm developing but I also want a stable version installed at the OS level. I write a Nix package and simply compose it into my overall NixOS configuration alongside the more official Nixpkgs: https://github.com/rraval/nix/blob/master/git-nomad.nix

> like a source code tarball where you would traditionally run configure && make && make install?

Nix has a bunch of defaults that make a conventional package like this straightforward.

Here's a package for a vanilla C binary + library that does the `autoreconf && ./configure && make && make install` dance: https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/secu...

It's almost a little misleading because the actual steps are largely inherited from the defaults, you can read more about `stdenv.mkDerivation` here: https://nixos.org/guides/nix-pills/fundamentals-of-stdenv.ht...

Re:Nix solves the package manager ejection problem on Monday May 31, 2021 @04:22PM (#27347742)
> I don't think it's a perfect analogy, but I see what the author is getting at - you need to break the abstraction of some packaging tool, but you want the functionality it provided to still work as well as possible.

You got it. I don't think it's the best analogy either but it is pithy and works if you squint.

The essence is:

1. create-react-app is a monolithic transformation of a bunch of disparate tools into a managed workflow.

2. You can update create-react-app like any other dependency and get updates to the workflow.

3. At any point, you can break the abstraction via `npm run eject`, which drops you down a level into the raw configuration for the "disparate tools" that create-react-app was acting as a veneer over. This ejection is a point in time transformation, you no longer get the managed workflow updates from (2).

The analogy was:

1. The Linux kernel package on $DISTRO is a monolithic transformation of Linux kernel source code to Linux kernel binaries.

2. You can get updates from the package manager.

3. At any point, you can break the abstraction by dropping down a level and forking the current packaging script to adjust the transformation (like applying a patch). This fork is a point in time transformation, you no longer get the package updates from (2).

Re:Nix solves the package manager ejection problem on Monday May 31, 2021 @04:02PM (#27347597)
Thanks, I didn't know about this. It's been about a decade since I actually used Gentoo and I was writing from the hip.

I've published a correction: https://zeroindexed.com/nix-ejection-problem#on-gentoo

My blog [1] has expanded commentary on the motivation:

> I thought that surely in 2021, somebody would have built a simple page view counter that I could just plug into my dinky blog for minimal cost. I ended up evaluating all the popular alternatives: Matamo, Plausible, and Cloudflare analytics.

> As it turns out, all of these are rather expensive. What should have been simple became bespoke and Toph was born. It’s a Cloudflare workers service that sits in between the visitors browser and Google Analytics.

I figured linking to the source code and README was more appropriate for Show HN.

[1]: https://zeroindexed.com/analytics

We use StackExchange's blackbox to check in GPG encrypted secrets into our monorepo: https://github.com/StackExchange/blackbox
Accumulating loop results in an array is bad for perf, but won't necessarily cause logic bugs.

My favourite implicit return gotcha comes from the intersection of CoffeeScript and jQuery, where implicitly returning `false` from an event handler implies `preventDefault()` and `stopPropagation()`. This can even cause heisenbugs if your logging throws booleans around.

Re:Show HN: Verify JSON using minimal schema on Thursday April 16, 2020 @11:45AM (#22890565)
> What statically typed language lets me define a type as “number between -180 and +180”, or “string which contains only alphanumeric chars”?

Pretty much all of them. Any simple predicate like this can be encoded with witness types.

Here's an example in Java, which is hardly the paragon of static typing (i.e. it's no Haskell/Idris/Agda/Rust/Typescript):

    class AlphaNumericString {
        private final String str;

        // use a fallible factory with a `private` constructor if you're
        // morally opposed to exceptions
        public AlphaNumericString(String str) throws AlphaNumericException {
            if (!str.matches("^[a-zA-Z0-9]*$")) {
                throw new AlphaNumericException();
            }

            this.str = str;
        }

        private static class AlphaNumericException extends Exception {
        }
    }
Now code can freely use `AlphaNumericString` and be guaranteed that it has been validated.

You may object and say that newtype wrapping is cumbersome but:

1. That's an argument about sugar and ergonomics, not about the semantics that the static type system enforces

2. Some languages make it easier to generate forwarding methods to the underlying type (a la https://kotlinlang.org/docs/reference/delegation.html)

3. The `AlphaNumericString` is describing a smaller set of values than `String`. In general, you should be strongly considering the methods you allow and make sure that all paths continue to enforce the semantics you intend.

Re:Using Makefile(s) for Go on Tuesday December 10, 2019 @08:09AM (#21752075)
This... isn't even using the `make` part of Makefiles at all.

If you look at the final example, every [1] rule is marked as `.PHONY`. `make` bundles 2 capabilities: a dependency graph and an out-of-date check to rebuild files. This demonstration uses neither.

The author would be better served with a shell script and a `case` block. The advantages:

- Functions! The `check-environment` rule is really a function call in disguise.

- No 2 phase execution. The author talks about using variables like `APP`, but those are make variables with very different semantics than shell variables (which are also available inside the recipes).

[1] Yes, there's a `check-environment` "rule" that isn't marked, but it likely should be since it isn't building a file target named `check-environment`.

Re:TypeScript 3.7 on Tuesday November 05, 2019 @08:05PM (#21458738)
> That being said though, I'd expect that a tuple would satisfy a `any[]` type.

You have it backwards, the error in question is complaining that `any[]` does not satisfy the tuple type.

Minimal repro:

    function f(x: any[]): [number, string] {
        return x;
    }
The error matches yours:

    Type 'any[]' is missing the following properties from type '[number, string]': 0, 1
From poking the playground, `any[]` hasn't been assignable to tuples since at least v3.3.3

My guess is that the compiler got smarter around reasoning about your `SinonSub` generic and is now forcing you to deal with lingering unsoundness.

That's fair, I too use a trucker's hitch for the ridgeline of a tarp.

However, I'll use adjustable grip hitches for the guylines. That lets me freely adjust how my tarp is placed and holds up the tension reasonably (from experience, the friction hitch on paracord could do with tightening every 1.5 days or so). It's also quicker to tie and uses less cordage, so that's a plus.

Combining the two straight up never occurred to me. Will definitely give that a shot :)

Incidentally, my favourite knot of all time is also listed first: the adjustable grip hitch, https://www.animatedknots.com/adjustable-grip-hitch-knot

Take 5 minutes out of your day, find a small piece of rope (or CAT5, headphone wire, USB cable), and actually tie the knot with your hands. It's super easy to pre-visualize the knot forming and you can learn to tie the knot in any orientation after just a couple tries.

Being able to adjust the tension on the line after tying the knot pops up in all manner of practical situations. This was my gateway drug to the wonderful world of knots.

---

EDIT: to encourage people to actually tie the damn thing, here's a picture of my computer mouse cable around the handle of my coffee cup: https://i.imgur.com/ZN4WXoB.jpg (in the "right handed down" orientation, as opposed the the "right handed up" direction from the instructions).

> If the username could be an email address (or the email address is a required field on signup) you don’t have to pass back a message saying that the username is already taken. You simply let them go through the flow and do verification of the email address by emailing and requiring clicking on a link, and if they are already signed up send a message saying someone tried to sign up with your email address.

Sure, let's play this out. Assume for simplicity that the username / user identifier is the email address for our example.

---

Someone comes to your site and tries to sign up with `[email protected]`. The system has never seen `[email protected]` so:

The system registers `[email protected]` in a pending state and sends an email link to `[email protected]` saying "Please click this link to finish the signup flow".

It also responds to the person signing up, saying "We've sent you an email, please click the link in your inbox to finish the signup flow".

---

Someone comes to your site and tries to signup with `[email protected]`. The system has an existing record of `[email protected]` and the password does not match.

The system sends an email to `[email protected]` saying that someone tried to sign up a new account with the wrong password.

It also responds to the person signing up, saying "We've sent you an email, please click the link in your inbox to finish the signup flow".

---

For a system as described, I concede that a third party has no means of checking if an email address has already signed up, the messages they receive are indistinguishable.

However, for this to work, the click-link-in-email step needs to be a synchronous part of your signup flow. I worry what this added friction does to the bounce rate. Although since I haven't measured it, maybe this worry is misplaced. And of course there's the caveat that measuring with statistically insignificant sample sizes in the early days of a product is its own can of worms.

I disagree with the section titled "Username enumeration and the impact on anonymity".

The author is trying to make the point that you shouldn't tell users that their username is invalid in a password reset flow. The author then goes further and recommends obscuring error messages during the login flow as well.

I find this behaviour to be user hostile and not particularly effective at concealing anonymity. Under the same threat model, a suitably motivated third party can simply attempt to sign up with the same username, and you'll definitely have an error message if the user is already signed up (and that's besides the point that just because a username exists doesn't mean the person behind that identifier actually signed up, anyone could've done it).

The author tries to justify their position by calling it a "slight usability tax" and "a small trade-off for an infrequent process", but my very short experience building a consumer oriented SaaS is that:

1. Password requests are frequent, even with ~5k users

2. Lots of people have more than one email address, and frequently forget which one they used for your service.

3. The support burden simply isn't worth the pseudo-anonymity.

As you say, I'd question the technical motivation for enforcing uniqueness on unicode data in the first place (and as a primary key on top of that???)

However, if someone really wanted to accomplish this, they could probably use PostgreSQL's functional indices and unicode normalization to do it.

> the solution for which is to use icu

We ran headfirst into this issue at my company and we've actually been recommending the opposite (use the "C" locale on the database, treat collation as a render level concern).

I have a whole write up explaining the technical motivations behind that recommendation: https://gist.github.com/rraval/ef4e4bdc63e68fe3e83c9f98f56af...

Re:Proposal: Go 2 transition on Friday October 26, 2018 @04:20PM (#18312436)
This is my attempt to be sympathetic to the GP's point of view, perhaps they have a different example in mind.

One example comes from the new-style / old-style classes distinction and the method resolution order when considering multiple inheritance.

Python 2.3 introduced "new-style" classes which inherit from `object` and use the C3 resolution algorithm [1]. For backwards compatibility reasons, "old-style" classes without an explicit `object` base class still used the old method resolution semantics.

Python 3 does away with "old-style" classes entirely and all classes must use the "new-style" semantics.

There's presumably a ton of code that doesn't specify `object` as an explicit base class, and thus may have subtle broken behaviour under "new-style". Given Python 3's inability / unwillingness to simulate the old behaviour, I'm unaware of any tool that's able to rewrite Python 2 to 3 in a bullet proof fashion [2].

This is not the same kind of breakage that other people mention, like `print` being a function or `reduce` being moved to `functools`. Those are simply backwards incompatible "movements", not outright removals, and thus can be rewritten by automated tools.

[1] https://www.python.org/download/releases/2.3/mro/ [2] https://portingguide.readthedocs.io/en/latest/classes.html#n...

Older »