poit-puller (0.1.0)

Published 2026-09-14 14:48:59 +00:00 by niro

Installation

[registries.forgejo]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add poit-puller@0.1.0 --registry forgejo

About this package

POIT Puller

A Rust client for listing and fetching Kallelser from Post- och Inrikes Tidningar (POIT).

Status

The client can:

  • list publications with amnesomradeId=1 for a date range;
  • fetch an individual publication by kungorelseid;
  • decode POIT's version 5 response format into JSON.

Persistence and scheduled polling still need to be implemented.

Requirements

  • A recent stable Rust toolchain

Install Rust with rustup if needed.

Library usage

use poit_puller::{PoitClient, Result};

async fn fetch() -> Result<()> {
    let client = PoitClient::new()?;
    let listings = client
        .list_kallelser("2026-09-14", "2026-09-14")
        .await?;
    let notice = client.fetch_announcement(&listings[0].kungorelseid).await?;
    println!("{notice:#}");
    Ok(())
}

PDF support

Enable the optional pdf feature to convert kungorelseText to PDF:

let pdf: Vec<u8> = client.fetch_announcement_pdf("K621433/26").await?;
std::fs::write("K621433-26.pdf", pdf)?;

The targeted renderer supports the HTML elements emitted by POIT: paragraphs, bold text, line breaks, and ordered or unordered lists. It uses built-in PDF fonts and an all-Rust dependency stack—no browser, wkhtmltopdf, system font, or native library is required.

Examples

List Kallelser for one day or a date range:

cargo run --example list -- 2026-09-14
cargo run --example list -- 2026-09-14 2026-09-16

Fetch and decode an individual publication:

cargo run --example fetch -- 'K621433/26'

The examples write pretty-printed JSON to standard output. Generate a PDF with:

cargo run --features pdf --example pdf -- 'K621433/26' output.pdf

How individual publications are decoded

The client follows the current POIT web application:

  1. Request a coupling token from HamtaKoppling using the same HTTP session.
  2. Request HamtaKungorelse with the publication ID, coupling token, and version=5.
  3. Reverse POIT's letter-case and digit transformation.
  4. Base64-decode the response.
  5. Derive a 32-byte state from SHA-256(kungorelseid + koppling).
  6. Apply POIT's mutable XOR routine and parse the resulting JSON.

Coupling token

HamtaKoppling returns a short-lived token that links a detail request to the current HTTP session. POIT also uses it when encoding the response: the decoder key state is derived from SHA-256(kungorelseid + koppling). The token and cookies must therefore be fetched dynamically and reused by the same client.

The client sends browser-like request headers because POIT otherwise returns its security challenge instead of API data.

Development

cargo fmt --check
cargo test
cargo clippy --all-targets --all-features

Dependencies

Dependencies

ID Version
base64 ^0.23.1
html-escape ^0.2.15
printpdf ^0.12.8
reqwest ^0.13.5
serde ^1.0.229
serde_json ^1.0.151
sha2 ^0.11.0
tokio ^1.53.1
Details
Cargo
2026-09-14 14:48:59 +00:00
1
580 KiB
Assets (1)
Versions (3) View all
0.3.0 2026-10-07
0.2.0 2026-09-14
0.1.0 2026-09-14