home.social

Search

343 results for “hongminhee”

  1. So, an interesting issue came up in the #Fedify repo that I've been thinking about: #629.

    You know how every #fediverse server uses schema:PropertyValue in actor attachment for profile metadata fields (like “Website”, “GitHub”, etc.)? Turns out, strict #AS2 validators like browser.pub reject it, because the AS2 spec says attachment should only contain Object or Link—and PropertyValue is a schema.org type, not an Activity Streams 2.0 type.

    The thing is, we can't just drop the type like we did with Endpoints (#576), because Mastodon and others rely on seeing "type": "PropertyValue" to render profile fields. But at the same time, it's technically not spec-compliant.

    I'm leaning towards writing a #FEP to formalize this existing practice rather than trying to invent a new type (like toot:PropertyValue extending Object), which would be a nightmare to migrate across the whole fediverse.

    What do you all think? Has anyone else run into this? Would love to hear thoughts from implementers and spec folks.

    #fedidev #ActivityPub #ActivityStreams #ActivityStreams2 #AS2 #PropertyValue

  2. So, an interesting issue came up in the #Fedify repo that I've been thinking about: #629.

    You know how every #fediverse server uses schema:PropertyValue in actor attachment for profile metadata fields (like “Website”, “GitHub”, etc.)? Turns out, strict #AS2 validators like browser.pub reject it, because the AS2 spec says attachment should only contain Object or Link—and PropertyValue is a schema.org type, not an Activity Streams 2.0 type.

    The thing is, we can't just drop the type like we did with Endpoints (#576), because Mastodon and others rely on seeing "type": "PropertyValue" to render profile fields. But at the same time, it's technically not spec-compliant.

    I'm leaning towards writing a #FEP to formalize this existing practice rather than trying to invent a new type (like toot:PropertyValue extending Object), which would be a nightmare to migrate across the whole fediverse.

    What do you all think? Has anyone else run into this? Would love to hear thoughts from implementers and spec folks.

    #fedidev #ActivityPub #ActivityStreams #ActivityStreams2 #AS2 #PropertyValue

  3. So, an interesting issue came up in the #Fedify repo that I've been thinking about: #629.

    You know how every #fediverse server uses schema:PropertyValue in actor attachment for profile metadata fields (like “Website”, “GitHub”, etc.)? Turns out, strict #AS2 validators like browser.pub reject it, because the AS2 spec says attachment should only contain Object or Link—and PropertyValue is a schema.org type, not an Activity Streams 2.0 type.

    The thing is, we can't just drop the type like we did with Endpoints (#576), because Mastodon and others rely on seeing "type": "PropertyValue" to render profile fields. But at the same time, it's technically not spec-compliant.

    I'm leaning towards writing a #FEP to formalize this existing practice rather than trying to invent a new type (like toot:PropertyValue extending Object), which would be a nightmare to migrate across the whole fediverse.

    What do you all think? Has anyone else run into this? Would love to hear thoughts from implementers and spec folks.

    #fedidev #ActivityPub #ActivityStreams #ActivityStreams2 #AS2 #PropertyValue

  4. So, an interesting issue came up in the #Fedify repo that I've been thinking about: #629.

    You know how every #fediverse server uses schema:PropertyValue in actor attachment for profile metadata fields (like “Website”, “GitHub”, etc.)? Turns out, strict #AS2 validators like browser.pub reject it, because the AS2 spec says attachment should only contain Object or Link—and PropertyValue is a schema.org type, not an Activity Streams 2.0 type.

    The thing is, we can't just drop the type like we did with Endpoints (#576), because Mastodon and others rely on seeing "type": "PropertyValue" to render profile fields. But at the same time, it's technically not spec-compliant.

    I'm leaning towards writing a #FEP to formalize this existing practice rather than trying to invent a new type (like toot:PropertyValue extending Object), which would be a nightmare to migrate across the whole fediverse.

    What do you all think? Has anyone else run into this? Would love to hear thoughts from implementers and spec folks.

    #fedidev #ActivityPub #ActivityStreams #ActivityStreams2 #AS2 #PropertyValue

  5. A daily minor annoyance: #GFM (GitHub Flavored Markdown) breaking standard #Markdown behavior by rendering single newlines as <br>.

    If you're used to formatting plain text with hard wraps for mailing lists, you know the pain. You type up a perfectly readable 80-column text block, hit submit, and realize #GitHub has turned it into a jagged mess of arbitrary line breaks. I really miss standard Markdown paragraph collapsing in issue trackers.

  6. Just had to add a workaround to #Fedify for http://joinmastodon.org/ns, a JSON-LD context URL that has never actually served a JSON-LD document. Mastodon has always inlined the term definitions, but some implementations put it as a bare URL in their @context, so Fedify's JSON-LD processor tries to fetch it and gets a 404 Not Found. Now Fedify ships a bundled copy of a context that never existed in the first place.

    https://github.com/fedify-dev/fedify/pull/631

    #fedidev #ActivityPub #JSONLD

  7. Optique just crossed 600 GitHub stars!

    For those unfamiliar: #Optique is a #CLI parsing library for #TypeScript that takes a parser combinator approach, inspired by Haskell's optparse-applicative. The core idea is “parse, don't validate”—you express constraints like mutually exclusive options or dependent flags through types, and TypeScript infers the rest automatically. No runtime validation boilerplate needed.

    It started as something I built out of frustration while working on Fedify, an ActivityPub framework, when no existing CLI library could express the constraints I needed in a type-safe way. Apparently I wasn't the only one who felt that way.

    Thank you all for the support.

    https://github.com/dahlia/optique

  8. Optique just crossed 600 GitHub stars!

    For those unfamiliar: #Optique is a #CLI parsing library for #TypeScript that takes a parser combinator approach, inspired by Haskell's optparse-applicative. The core idea is “parse, don't validate”—you express constraints like mutually exclusive options or dependent flags through types, and TypeScript infers the rest automatically. No runtime validation boilerplate needed.

    It started as something I built out of frustration while working on Fedify, an ActivityPub framework, when no existing CLI library could express the constraints I needed in a type-safe way. Apparently I wasn't the only one who felt that way.

    Thank you all for the support.

    https://github.com/dahlia/optique

  9. Optique just crossed 600 GitHub stars!

    For those unfamiliar: #Optique is a #CLI parsing library for #TypeScript that takes a parser combinator approach, inspired by Haskell's optparse-applicative. The core idea is “parse, don't validate”—you express constraints like mutually exclusive options or dependent flags through types, and TypeScript infers the rest automatically. No runtime validation boilerplate needed.

    It started as something I built out of frustration while working on Fedify, an ActivityPub framework, when no existing CLI library could express the constraints I needed in a type-safe way. Apparently I wasn't the only one who felt that way.

    Thank you all for the support.

    https://github.com/dahlia/optique

  10. Optique just crossed 600 GitHub stars!

    For those unfamiliar: #Optique is a #CLI parsing library for #TypeScript that takes a parser combinator approach, inspired by Haskell's optparse-applicative. The core idea is “parse, don't validate”—you express constraints like mutually exclusive options or dependent flags through types, and TypeScript infers the rest automatically. No runtime validation boilerplate needed.

    It started as something I built out of frustration while working on Fedify, an ActivityPub framework, when no existing CLI library could express the constraints I needed in a type-safe way. Apparently I wasn't the only one who felt that way.

    Thank you all for the support.

    https://github.com/dahlia/optique

  11. Optique just crossed 600 GitHub stars!

    For those unfamiliar: #Optique is a #CLI parsing library for #TypeScript that takes a parser combinator approach, inspired by Haskell's optparse-applicative. The core idea is “parse, don't validate”—you express constraints like mutually exclusive options or dependent flags through types, and TypeScript infers the rest automatically. No runtime validation boilerplate needed.

    It started as something I built out of frustration while working on Fedify, an ActivityPub framework, when no existing CLI library could express the constraints I needed in a type-safe way. Apparently I wasn't the only one who felt that way.

    Thank you all for the support.

    https://github.com/dahlia/optique

  12. I've been increasingly concerned about the corporate monopoly over frontier LLMs. While many ethically-minded people choose to boycott these models, I believe passive resistance alone cannot break the structural grip of big tech. To truly “liberate” these technologies and turn them into public goods, we need to look beyond moral high grounds and engage with the material basis of AI—specifically compute, data, and the relations of production.

    I've written two posts exploring this through the lens of historical materialism. The first piece analyzes why current “open source” definitions struggle with LLMs, and the second discusses what it means to “act materialistically” in our imperfect world. My goal is to suggest a path forward that moves from mere boycotting to a more proactive, structural socialization of AI infrastructure.

    If you've been feeling uneasy about the AI landscape but aren't sure if boycotting is the final answer, I'd love for you to give these a read:

    #LLM #AI #opensource #historicalmaterialism #histomat #materialism #digitalcommons

  13. 以前から、東アジアにもFediConのようなイベントがあればいいなと言い続けてきました。独自のカンファレンスはまだ難しそうですが、小さな一歩として考えていることがあります。

    @COSCUP 2026(台北、8月8日〜9日)がコミュニティトラックの提案を受け付けています。FOSDEMのSocial Web devroomのような感じで、Social Webトラックを開けないかなと思っているところです。

    まだ構想段階ですが、ActivityPubやフェディバース、ソーシャルウェブ全般に取り組んでいて、発表や共同オーガナイズに興味があるという方がいれば、ぜひ話しかけてください。

    https://floss.social/@COSCUP/116152356550445285

    #SocialWeb #ActivityPub #fediverse #フェディバース #COSCUP #fedidev

  14. 東(동)아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 番(번) 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

    @COSCUP 2026(臺北(타이베이), 8月(월) 8日(일)–9日(일))이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

    아직 確定(확정)된 건 아무것도 없지만, #ActivityPub, #聯合宇宙(연합우주), 或(혹)은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)나 共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

    https://floss.social/@COSCUP/116152356550445285

    #SocialWeb #fediverse #연합우주 #페디버스 #COSCUP #fedidev

  15. 東(동)아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 番(번) 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

    @COSCUP 2026(臺北(타이베이), 8月(월) 8日(일)–9日(일))이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

    아직 確定(확정)된 건 아무것도 없지만, #ActivityPub, #聯合宇宙(연합우주), 或(혹)은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)나 共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

    https://floss.social/@COSCUP/116152356550445285

    #SocialWeb #fediverse #연합우주 #페디버스 #COSCUP #fedidev

  16. 東(동)아시아에도 FediCon 같은 行事(행사)가 있으면 좋겠다는 말을 여러 番(번) 해왔는데요. 獨立的(독립적)인 컨퍼런스는 아직 어렵더라도, 작은 첫걸음으로 생각해보고 있는 게 있습니다.

    @COSCUP 2026(臺北(타이베이), 8月(월) 8日(일)–9日(일))이 커뮤니티 트랙 提案(제안)을 받고 있어요. FOSDEM의 Social Web devroom 같은 느낌으로, 거기서 Social Web 트랙을 열 수 있지 않을까 하고 構想(구상) 중입니다.

    아직 確定(확정)된 건 아무것도 없지만, #ActivityPub, #聯合宇宙(연합우주), 或(혹)은 소셜 웹 全般(전반)을 다루고 있고 發表(발표)나 共同(공동) 오거나이징에 關心(관심)이 있으신 분이 있다면 이야기 걸어주세요.

    https://floss.social/@COSCUP/116152356550445285

    #SocialWeb #fediverse #연합우주 #페디버스 #COSCUP #fedidev

  17. Today @kopper shared a post on the fediverse titled how to not regret c2s, and I found it genuinely interesting to read, even if I'm not sure its proposed architecture actually solves what it sets out to solve.

    The author's frustration with naïve #C2S implementations is well-founded. Slapping an #ActivityPub facade onto an existing Mastodon-like server and calling it C2S doesn't buy you much—you end up with the rigidity of a bespoke API without any of the interoperability C2S is supposed to offer. The “JSON-LD flavored Mastodon API” framing is apt.

    The proposed solution is to split responsibility more aggressively: the C2S server should be nearly stateless and dumb, storing ActivityPub objects without interpreting them, while a separate “client” layer handles indexing, timelines, moderation, and exposes its own API to the frontend running on the user's device. It's a clean separation of concerns on paper.

    But here's what bothers me. When you map this architecture onto familiar terms, it looks roughly like this:

    • C2S server ≈ a database (PostgreSQL, say)
    • “Client” ≈ an application server (Mastodon, Misskey)
    • “Frontend” ≈ the actual client app on your phone

    That's not a new architecture. That's just the current architecture with the labels shifted. The interesting question is which interface gets standardized, and the author's answer is the one between the C2S server and the “client” layer—the bottom boundary.

    The problem is that what people actually want from C2S is to connect any frontend to any server. The portability they're after lives at the top boundary, between the frontend and whatever is behind it. But the author explicitly argues against standardizing that layer: “we don't really need a standardized api,” they write, leaving each client free to expose whatever API it likes.

    Which means frontends remain locked to specific clients, just as Mastodon apps are locked to the Mastodon API today. The interoperability promise of C2S—log in to any server with any app—isn't actually delivered. It's been pushed one layer down, out of reach of the end user.

    There's real value in the post's thinking about data hosting vs. interpretation, and about the security implications of servers that understand too much. But as an answer to the question C2S is supposed to answer, I'm not convinced.

    #fedidev #fediverse

  18. When I first started working with #ActivityPub, before #Fedify existed, it felt like writing web apps in Perl and CGI in the late '90s. Interesting, even exciting—but never comfortable. That era where your business logic and your protocol plumbing were just… the same thing:

    print "HTTP/1.1 200 OK"
    print "Content-Type: text/html"
    print
    print "Hello, world!"

    Decades of web development have given us layers of abstraction we now take for granted. Nobody hand-parses application/x-www-form-urlencoded query strings anymore. Nobody writes their own JSON codec, or manually constructs HTTP request/response messages. These things just aren't your problem when you're building an app.

    ActivityPub development still feels like they are your problem. What do you do when the https://www.w3.org/ns/activitystreams#actor property comes in as a string instead of an array? What about when https://www.w3.org/ns/activitystreams#object is an embedded entity rather than a URI? How exactly do you implement HTTP Signatures? And wait—what's Linked Data Signatures, and do you need that too?

    The real issue isn't that ActivityPub is complicated per se. It's that you can't get away with understanding it at a high level. You have to know it the way an implementor knows it—every edge case, every inconsistency in how different servers serialize JSON-LD, every signature scheme that exists in the wild. That's a lot to learn before you can even start thinking about your actual app. And when developers understandably cut corners on the protocol to focus on their product, it quietly becomes an interoperability problem for the whole ecosystem.

    What I want ActivityPub development to feel like: you spend a day understanding the big picture, and then you just… build your app. That was the goal when I started Fedify, and honestly, we're not fully there yet. But it's where I want to get.

    #fedidev #fediverse

  19. Started laying out a rough plan for implementing FEP-ef61: Portable Objects in #Fedify—server-independent #ActivityPub identities backed by #DIDs, multi-server replication, and client-side signing. It's going to be a long road (13 tasks across 5 phases, with a few open questions that need answering before we even begin), but I think it's worth doing right.

    https://github.com/fedify-dev/fedify/issues/288#issuecomment-3971459585

    #fedidev #fediverse #PortableObjects

  20. There's now a proper rendered web interface for FEPs at https://fediverse.codeberg.page/fep/fep/*/, which is much nicer to read than the raw Markdown source on Codeberg. But the canonical permalink, https://w3id.org/fep/*, still redirects to the Markdown file rather than the rendered page.

    Would it make sense to update the w3id.org redirect to point to the rendered version instead? It seems like the better experience for anyone following a FEP link, and arguably what a “permanent” link should resolve to—something human-readable.

    I'm not sure who manages the w3id.org/fep/ redirect configuration. (It lives in the perma-id/w3id.org GitHub repo, so it would just be a PR, but I'd want to get community consensus first rather than just send one in unilaterally.)

    #fedidev #fep #fediverse #ActivityPub

  21. #Optique 1.0.0 preview: runWithConfig() is gone—run() now accepts source contexts. Meta command config gets independent command/option sub-configs. bindConfig() gains config-file metadata for path resolution. #TypeScript #CLI

    dahlia/optique

  22. #Optique 1.0.0 is shaping up, and three API changes are worth knowing about in advance.

    • Runner consolidation: run() from @optique/run now accepts source contexts directly, which makes runWith() and runWithConfig() redundant for most use cases. runWithConfig() is removed outright—no deprecation, since we have a major version to absorb the break. For the typical CLI, run() is now the single entry point.

    • Meta command config redesign: help, version, and completion in RunOptions no longer use mode: "command" | "option" | "both". Each now takes independent command and option sub-configs, which makes it possible to give --help a -h alias, hide a meta command from usage lines while keeping it in the help listing, or group the command and option forms differently. String shorthands (help: "both", version: "1.2.3", etc.) still work exactly as before.

    • Config-file-relative paths: bindConfig()'s key callback now receives config file metadata as a second argument—configDir and configPath—so you can resolve paths relative to the config file's location rather than the working directory. This matches how tools like the TypeScript compiler handle outDir and similar path options.

    More details on the 1.0.0 milestone.

  23. #Optique 1.0.0 is shaping up, and three API changes are worth knowing about in advance.

    • Runner consolidation: run() from @optique/run now accepts source contexts directly, which makes runWith() and runWithConfig() redundant for most use cases. runWithConfig() is removed outright—no deprecation, since we have a major version to absorb the break. For the typical CLI, run() is now the single entry point.

    • Meta command config redesign: help, version, and completion in RunOptions no longer use mode: "command" | "option" | "both". Each now takes independent command and option sub-configs, which makes it possible to give --help a -h alias, hide a meta command from usage lines while keeping it in the help listing, or group the command and option forms differently. String shorthands (help: "both", version: "1.2.3", etc.) still work exactly as before.

    • Config-file-relative paths: bindConfig()'s key callback now receives config file metadata as a second argument—configDir and configPath—so you can resolve paths relative to the config file's location rather than the working directory. This matches how tools like the TypeScript compiler handle outDir and similar path options.

    More details on the 1.0.0 milestone.

  24. #Optique 1.0.0 is shaping up, and three API changes are worth knowing about in advance.

    • Runner consolidation: run() from @optique/run now accepts source contexts directly, which makes runWith() and runWithConfig() redundant for most use cases. runWithConfig() is removed outright—no deprecation, since we have a major version to absorb the break. For the typical CLI, run() is now the single entry point.

    • Meta command config redesign: help, version, and completion in RunOptions no longer use mode: "command" | "option" | "both". Each now takes independent command and option sub-configs, which makes it possible to give --help a -h alias, hide a meta command from usage lines while keeping it in the help listing, or group the command and option forms differently. String shorthands (help: "both", version: "1.2.3", etc.) still work exactly as before.

    • Config-file-relative paths: bindConfig()'s key callback now receives config file metadata as a second argument—configDir and configPath—so you can resolve paths relative to the config file's location rather than the working directory. This matches how tools like the TypeScript compiler handle outDir and similar path options.

    More details on the 1.0.0 milestone.

  25. #Optique 1.0.0 is shaping up, and three API changes are worth knowing about in advance.

    • Runner consolidation: run() from @optique/run now accepts source contexts directly, which makes runWith() and runWithConfig() redundant for most use cases. runWithConfig() is removed outright—no deprecation, since we have a major version to absorb the break. For the typical CLI, run() is now the single entry point.

    • Meta command config redesign: help, version, and completion in RunOptions no longer use mode: "command" | "option" | "both". Each now takes independent command and option sub-configs, which makes it possible to give --help a -h alias, hide a meta command from usage lines while keeping it in the help listing, or group the command and option forms differently. String shorthands (help: "both", version: "1.2.3", etc.) still work exactly as before.

    • Config-file-relative paths: bindConfig()'s key callback now receives config file metadata as a second argument—configDir and configPath—so you can resolve paths relative to the config file's location rather than the working directory. This matches how tools like the TypeScript compiler handle outDir and similar path options.

    More details on the 1.0.0 milestone.

  26. #Optique 1.0.0 is shaping up, and three API changes are worth knowing about in advance.

    • Runner consolidation: run() from @optique/run now accepts source contexts directly, which makes runWith() and runWithConfig() redundant for most use cases. runWithConfig() is removed outright—no deprecation, since we have a major version to absorb the break. For the typical CLI, run() is now the single entry point.

    • Meta command config redesign: help, version, and completion in RunOptions no longer use mode: "command" | "option" | "both". Each now takes independent command and option sub-configs, which makes it possible to give --help a -h alias, hide a meta command from usage lines while keeping it in the help listing, or group the command and option forms differently. String shorthands (help: "both", version: "1.2.3", etc.) still work exactly as before.

    • Config-file-relative paths: bindConfig()'s key callback now receives config file metadata as a second argument—configDir and configPath—so you can resolve paths relative to the config file's location rather than the working directory. This matches how tools like the TypeScript compiler handle outDir and similar path options.

    More details on the 1.0.0 milestone.

  27. A couple days ago, I got a DM from a #Bonfire user. I happily replied and sent a follow request—but the Accept never came back, even though they hadn't enabled manuallyApprovesFollowers. My DM reply probably never arrived either. Classic interop bug.

    I checked out the Bonfire source and dug in. Turns out Bonfire hasn't implemented RFC 9421 yet, so it was silently discarding any activity signed with it. That alone would be workable, except for one more issue: Bonfire was responding 200 OK even when signature verification failed, instead of 401 Unauthorized.

    This matters because Fedify implements a double-knocking mechanism—if a request signed with RFC 9421 fails, it retries with the older draft cavage signature. But since Bonfire returned 200 OK on the failed first knock, #Fedify had no reason to send a second one.

    I filed two issues on the Bonfire #ActivityPub repo—one requesting RFC 9421 support, and one about returning 401 on invalid signatures. For the latter, I also sent a PR, which got merged pretty quickly: bonfire-networks/activity_pub#9.

    That said, individual Bonfire instances won't pick up the fix until they actually deploy it. So in the meantime, I patched Hollo and Hackers' Pub to use draft-cavage-http-signatures-12 as the firstKnock, so Bonfire instances can at least understand the first request.

    One last thing: Fedify caches whether a given server supports RFC 9421, and the Bonfire servers I'd already talked to were cached as “supports RFC 9421”—because they'd been returning 200 OK. I had to manually clear that cache on both hollo.social and hackers.pub before everything finally worked.

    After all that, the mutual follow went through and my DM reply landed. Worth it.

    #fedidev #fediverse #Hollo #HackersPub

  28. A couple days ago, I got a DM from a #Bonfire user. I happily replied and sent a follow request—but the Accept never came back, even though they hadn't enabled manuallyApprovesFollowers. My DM reply probably never arrived either. Classic interop bug.

    I checked out the Bonfire source and dug in. Turns out Bonfire hasn't implemented RFC 9421 yet, so it was silently discarding any activity signed with it. That alone would be workable, except for one more issue: Bonfire was responding 200 OK even when signature verification failed, instead of 401 Unauthorized.

    This matters because Fedify implements a double-knocking mechanism—if a request signed with RFC 9421 fails, it retries with the older draft cavage signature. But since Bonfire returned 200 OK on the failed first knock, #Fedify had no reason to send a second one.

    I filed two issues on the Bonfire #ActivityPub repo—one requesting RFC 9421 support, and one about returning 401 on invalid signatures. For the latter, I also sent a PR, which got merged pretty quickly: bonfire-networks/activity_pub#9.

    That said, individual Bonfire instances won't pick up the fix until they actually deploy it. So in the meantime, I patched Hollo and Hackers' Pub to use draft-cavage-http-signatures-12 as the firstKnock, so Bonfire instances can at least understand the first request.

    One last thing: Fedify caches whether a given server supports RFC 9421, and the Bonfire servers I'd already talked to were cached as “supports RFC 9421”—because they'd been returning 200 OK. I had to manually clear that cache on both hollo.social and hackers.pub before everything finally worked.

    After all that, the mutual follow went through and my DM reply landed. Worth it.

    #fedidev #fediverse #Hollo #HackersPub

  29. A couple days ago, I got a DM from a #Bonfire user. I happily replied and sent a follow request—but the Accept never came back, even though they hadn't enabled manuallyApprovesFollowers. My DM reply probably never arrived either. Classic interop bug.

    I checked out the Bonfire source and dug in. Turns out Bonfire hasn't implemented RFC 9421 yet, so it was silently discarding any activity signed with it. That alone would be workable, except for one more issue: Bonfire was responding 200 OK even when signature verification failed, instead of 401 Unauthorized.

    This matters because Fedify implements a double-knocking mechanism—if a request signed with RFC 9421 fails, it retries with the older draft cavage signature. But since Bonfire returned 200 OK on the failed first knock, #Fedify had no reason to send a second one.

    I filed two issues on the Bonfire #ActivityPub repo—one requesting RFC 9421 support, and one about returning 401 on invalid signatures. For the latter, I also sent a PR, which got merged pretty quickly: bonfire-networks/activity_pub#9.

    That said, individual Bonfire instances won't pick up the fix until they actually deploy it. So in the meantime, I patched Hollo and Hackers' Pub to use draft-cavage-http-signatures-12 as the firstKnock, so Bonfire instances can at least understand the first request.

    One last thing: Fedify caches whether a given server supports RFC 9421, and the Bonfire servers I'd already talked to were cached as “supports RFC 9421”—because they'd been returning 200 OK. I had to manually clear that cache on both hollo.social and hackers.pub before everything finally worked.

    After all that, the mutual follow went through and my DM reply landed. Worth it.

    #fedidev #fediverse #Hollo #HackersPub

  30. A couple days ago, I got a DM from a #Bonfire user. I happily replied and sent a follow request—but the Accept never came back, even though they hadn't enabled manuallyApprovesFollowers. My DM reply probably never arrived either. Classic interop bug.

    I checked out the Bonfire source and dug in. Turns out Bonfire hasn't implemented RFC 9421 yet, so it was silently discarding any activity signed with it. That alone would be workable, except for one more issue: Bonfire was responding 200 OK even when signature verification failed, instead of 401 Unauthorized.

    This matters because Fedify implements a double-knocking mechanism—if a request signed with RFC 9421 fails, it retries with the older draft cavage signature. But since Bonfire returned 200 OK on the failed first knock, #Fedify had no reason to send a second one.

    I filed two issues on the Bonfire #ActivityPub repo—one requesting RFC 9421 support, and one about returning 401 on invalid signatures. For the latter, I also sent a PR, which got merged pretty quickly: bonfire-networks/activity_pub#9.

    That said, individual Bonfire instances won't pick up the fix until they actually deploy it. So in the meantime, I patched Hollo and Hackers' Pub to use draft-cavage-http-signatures-12 as the firstKnock, so Bonfire instances can at least understand the first request.

    One last thing: Fedify caches whether a given server supports RFC 9421, and the Bonfire servers I'd already talked to were cached as “supports RFC 9421”—because they'd been returning 200 OK. I had to manually clear that cache on both hollo.social and hackers.pub before everything finally worked.

    After all that, the mutual follow went through and my DM reply landed. Worth it.

    #fedidev #fediverse #Hollo #HackersPub