Compare commits

...

2 commits

Author SHA1 Message Date
randogoth
c5ad8d44e9 chore: release 0.3.1
Some checks failed
CI / macos (push) Failing after 1m8s
Release / macos (push) Failing after 47s
CI / linux (push) Successful in 4m47s
Release / linux (push) Successful in 3m42s
Release / flatpak (push) Successful in 3m9s
Release / release (push) Successful in 55s
CI / windows (push) Has been cancelled
Release / windows (push) Has been cancelled
Trims the body before signing it, so a trailing newline from the compose
buffer no longer ends up in the payload. A published record can't contain a
line break, so every post sent from here to a twtxt feed was refused.

Builds against fumi-core 0.1.1, which hands an accept token to a contact once
instead of attaching it to every message.
2026-10-15 09:23:20 +03:00
randogoth
d9798a18f1 fix: trim the body before signing it
The compose buffer was passed through verbatim, so whatever the author last
pressed ended up in the payload — usually a trailing newline. That is not
content, but it becomes content the moment it is signed, and nothing
downstream can remove it without invalidating the signature.

smolboid refuses any post whose text carries a line break, because a published
record is one line of a feed, so every post sent from carrier was rejected
with "contains TAB, LF, CR or U+2028". Trimming has to happen here, before the
seal, rather than at the receiver: stripping is not invertible, so a receiver
that trimmed could no longer rebuild the bytes the author signed.
2026-10-14 22:08:55 +03:00
4 changed files with 12 additions and 4 deletions

4
Cargo.lock generated
View file

@ -116,7 +116,7 @@ dependencies = [
[[package]]
name = "carrier"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"fluent-bundle",
"fumi-core",
@ -430,7 +430,7 @@ dependencies = [
[[package]]
name = "fumi-core"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"chacha20poly1305",
"data-encoding",

View file

@ -1,6 +1,6 @@
[package]
name = "carrier"
version = "0.3.0"
version = "0.3.1"
edition = "2021"
description = "A minimalist smolmail client built on fumi-core, with a Relm4 UI"
license = "Apache-2.0"

View file

@ -14,6 +14,7 @@
</description>
<launchable type="desktop-id">com.randogoth.carrier.desktop</launchable>
<releases>
<release version="0.3.1" date="2026-10-15"/>
<release version="0.3.0" date="2026-10-14"/>
<release version="0.2.0" date="2026-10-08"/>
<release version="0.1.0" date="2026-10-03"/>

View file

@ -716,7 +716,14 @@ pub fn send(
.collect();
let draft = client::SendDraft {
address: &addr,
text: body.to_string(),
// Trimmed at the send site, before the payload is signed, so the
// signature covers exactly the text the author meant. A compose buffer
// ends with whatever the author last pressed, and a trailing newline
// is not content — but it is content once it has been signed, and
// nothing downstream can remove it without invalidating the
// signature. smolboid, for one, refuses a post whose text carries a
// line break, because a published record is one line of a feed.
text: body.trim().to_string(),
subject,
reply_to,
headers: &owned,