☕ Kafumu

The Open Location Network

Kafumu's local messages are part of an open network anyone can read from, write to and run a node of. Here's how it works and how to connect.

What it is

The Open Location Network is a way to leave short public messages at a place without accounts, servers you must trust, or location tracking. A message is plain text plus hashtags. The place is a hashtag too: #geo followed by the first six characters of the area's plus code (about 5 km across), e.g. #geo8ccgmw. Anyone can store, index and pass these messages on; a node is just something that does that.

Instead of an account, every message carries a small proof of work: the sender's device tries numbers until the message's SHA-1 hash starts with enough zero bits. One message costs a phone a fraction of a second; a thousand cost a spammer real time. More work buys a longer life: a message lives one hour at the required work and twice as long for every extra bit (up to a week). When an area gets busy, the required work goes up a little, so floods price themselves out.

The proof of concept

OLN started as eolnpoc, a small Go proof of concept from long before Kafumu, and Kafumu speaks its format exactly, so messages move between the two unchanged. Kafumu is one OLN node: its local messages, questions, answers and reactions are all OLN messages.

The message format

nonce;YYYYMMDDhhmmss;base64url(text);#geo8ccgmw #langeng #coffee

The work is the number of leading zero bits of SHA-1 over the whole line. The message id is the hex SHA-1 of the line.

Reading: GET /oln.json

Live messages of a cell and its neighbours, in eolnpoc's olnjson format (server info, messages by id, a tag index, and where to push):

curl 'https://kafumu.com/oln.json?cell=8ccgmw'

Writing: POST /api/oln

First ask how much work the cell currently wants, then mine and post the raw line:

curl 'https://kafumu.com/api/oln/required?cell=8ccgmw'      # {"bits": 12}
curl -X POST --data-binary 'nonce;20261004183000;SGVsbG8;#geo8ccgmw' https://kafumu.com/api/oln

Answers: 200 with the stored message (and its expiry), 402 when the work is too low (mine more bits), 400 for a malformed line, a clock off by more than ten minutes, or not exactly one #geo cell.

Mining in JavaScript, in a few lines:

// sha1 → leading zero bits; try nonces until there are enough.
async function mine(text, keywords, bits) {
  const date = new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
  const b64 = btoa(String.fromCharCode(...new TextEncoder().encode(text)))
    .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
  for (let n = 0; ; n++) {
    const line = `${n};${date};${b64};${keywords}`;
    const h = new Uint8Array(await crypto.subtle.digest("SHA-1", new TextEncoder().encode(line)));
    let z = 0; for (const b of h) { if (b === 0) { z += 8; continue; } z += Math.clz32(b) - 24; break; }
    if (z >= bits) return line;
  }
}

Questions by subject: GET /api/asks

Live questions (#ask) about any of the given subjects, from anywhere; filter by distance yourself:

curl 'https://kafumu.com/api/asks?tags=opensource,esperanto'

Run your own node

Store messages you receive, serve them as oln.json, accept posts with enough work, and pull from or push to other nodes (Kafumu lists /api/oln as its push address). The source of Kafumu is open, and so is eolnpoc.