TIL: Browsers ignore Expires header on reload

Michał ‘mina86’ Nazarewicz | 26 lutego 2019

This may have been obvious, but I’ve just learned that browsers ignore Expires header when the user manually reloads the page (as in by pressing F5 or choosing Reload option).

I’ve run into this when testing how Firefox treats pages which ‘never’ expire. To my surprise, the browser made requests for files it had a fresh copy of in its cache. To see behaviour much more representative of the experience of a returning user, one should select the address bar (Alt+D does the trick) and then press Return to navigate to the current page again. Hitting Reload is more akin, though not exactly the same, to the first visit.

Of course, all of the above applies to the max-age directive of the Cache-Control header as well.

Moral of the story? Make sure you test the actual real-life scenarios before making any decisions.

Setting up Tor hidden service

Michał ‘mina86’ Nazarewicz | 17 lutego 2019

Anyone can think of myriad reasons to run a Tor hidden service. Surely many unsavoury endeavours spring to mind but of course, there are as many noble ones. There are also various pragmatic causes like circumventing lousy NATs. Me? I just wanted to play around with my router.

Configuring a hidden service is actually straightforward so to make things more interesting, this article will cover configuring a hidden service on a Turris Omnia router with the help of Linux Containers to maximise isolation of components. While some steps will be Omnia-specific, most translate easily to other systems, so this post may be applicable regardless of the distribution used.

Java: String↔char[]

Michał ‘mina86’ Nazarewicz | 9 lutego 2019

Do you recall when I decided to abuse Go’s run-time and play with string[]byte conversion? Fun times… I wonder if we could do the same to Java?

To remind ourselves of the ‘problem’, strings in Java are immutable but because Java has no concept of ownership or const keyword (can we move the industry to Rust already?) to make true on that promise, Java run-time has to make a defensive copy each time a new string is created or when string’s characters are returned.

Alas, do not despair! There is another way (exception handling elided for brevity):

private static Field getValueField() {
	final Field field = String.class.getDeclaredField("value");
	field.setAccessible(true);
	/* Test that it works. */
	final char[] chars = new char[]{'F', 'o', 'o'};
	final String string = new String();
	field.set(string, chars);
	if (string.equals("Foo") && field.get(string) == chars) {
		return field;
	}
	throw new UnsupportedOperationException(
		"UnsafeString not supported by the run-time");
}

private final static Field valueField = getValueField();

public static String fromChars(final char[] chars) {
	final String string = new String();
	valueField.set(string, chars);
	return string;
}

public static char[] toChars(final String string) {
	return (char[]) valueField.get(string);
}

However. There is a twist…

Calculating sRGB↔XYZ matrix

Michał ‘mina86’ Nazarewicz | 3 lutego 2019

I’ve recently found myself in need of an sRGB↔XYZ transformation matrix expressed to the maximum possible precision. Sources on the Internet typically limit the precision to just a few decimal places so I've decided to do the calculations by myself.

What we’re looking for is a 3-by-3 matrix \(M\) which, when multiplied by red, green and blue coördinates of a colour, produces its XYZ coördinates. In other words, a change of basis matrix from a space whose basis vectors are sRGB’s primary colours: $$ M = \begin{bmatrix} X_r & X_g & Y_b \\ Y_r & Y_g & Y_b \\ Z_r & Z_g & Z_b \end{bmatrix} $$

PSA: Yes, 64-byte key file is OK

Michał ‘mina86’ Nazarewicz | 4 kwietnia 2017

In an earlier entry I’ve changed generated key file used for disk encryption from 4096 to meagre 64 bytes. I gave no mention of that adjustment considering it unimportant but have since been enquired about security of such a short password.

Rest assured, a 64-byte key file is sufficient for any symmetric encryption (disk encryption being one example) and anything more does not improve security.

Go: string↔[]byte

Michał ‘mina86’ Nazarewicz | 28 lutego 2017

Yes… I’ve started coding in Go recently. It lacks many things but the one feature relevant to this post is const keyword. Arrays and slices in particular are always mutable and so equivalent of C’s const char * does not exist.

On the other hand, strings are immutable which means that conversion between a string and []byte requires memory allocation and copying of the data¹. Often this might be acceptable but to squeeze every last cycle the following two functions might help achieve zero-copy implementation:

func String(bytes []byte) string {
	hdr := *(*reflect.SliceHeader)(unsafe.Pointer(&bytes))
	return *(*string)(unsafe.Pointer(&reflect.StringHeader{
		Data: hdr.Data,
		Len:  hdr.Len,
	}))
}

func Bytes(str string) []byte {
	hdr := *(*reflect.StringHeader)(unsafe.Pointer(&str))
	return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
		Data: hdr.Data,
		Len:  hdr.Len,
		Cap:  hdr.Len,
	}))
}

Depending on the length of the strings, the difference in performance might be noticeable:

PSA: Creating world-unreadable files

Michał ‘mina86’ Nazarewicz | 5 lutego 2017

I’ve been reading tutorials on using key files for disk encryption. Common approach for creating such a file is:

Step 1: Create a random key file

head -c 4096 /dev/urandom >keyfile

Step 2: Make the file readable by owner only

chmod 400 keyfile

*sighs* Please, stop doing this and spreading that method. The correct way of achieving the effect is:

Step 1: Create a random key file readable by owner only

(umask 077; head -c 64 /dev/random >keyfile)

Or if the file needs to be created as root while command is run by a different user:

Step 1: Create a random key file readable by root only

sudo sh -c 'umask 077; head -c 64 /dev/random >keyfile'

The first method creates the file as world-readable¹ and before its permission are changed anyone can read it. The second method creates the file as readable only by its owner from the very beginning thus preventing the secret disclosure.

Generating random reals

Michał ‘mina86’ Nazarewicz | 26 grudnia 2016

A well known way of generating random floating point numbers in the presence of a pseudo-random number generator (PRNG) is to divide output of the latter by one plus its maximum possible return value.

extern uint64_t random_uint64(void);

double random_double(void) {
	return random_uint64() / (UINT64_MAX + 1.0);
}

This method is simple, effective, inefficient and wrong on a few levels.

Poradnik wyboru prezentów

Michał ‘mina86’ Nazarewicz | 25 listopada 2016

Tak, ponownie nadeszła ta pora raku. Musisz się postarać, jeśli chcesz być/pozostać ulubioną ciocią, wujkiem, bratem, siostrą lub rodzicem. Ale jak z szerokiego asortymentu zabawek, wybrać najlepszy prezent?

Niestety nie mam odpowiedzi na wszystkie pytania, ale poniższy diagram może pomóc w przynajmniej jednym aspekcie:

Diagram „Czy zabawka jest dla chłopców czy dziewczynek?”

Strach

Michał ‘mina86’ Nazarewicz | 28 września 2016

English version available on The Codeless Code.

Niedawno przyjęty do świątyni mnich zbliżył się do mistrza.

― Otrzymałem zadanie dodania kilku nowych funkcji do systemu obsługi zamówień Cesarskiego Szewca, ale nie jestem w stanie zrozumieć, jak on działa. Logika jest rozproszona pomiędzy wiele aplikacji zaimplementowanych przy użyciu najróżniejszych technologii. Zamiast stworzyć wspólne biblioteki, autorzy najzwyklej skopiowali fragmenty kodu pomiędzy różnymi miejscami, często wprowadzając subtelne rozbieżności. Zadania pracujące w tle wyszukują i modyfikują rekordy w bazie danych bez żadnego udokumentowanego powodu. Sama baza danych wydaje się spiskować przeciwko mnie: prosta modyfikacja jednej tabeli może wyzwolić kaskadę zmian w wielu innych.