{"id":380,"date":"2026-09-21T00:06:22","date_gmt":"2026-09-20T22:06:22","guid":{"rendered":"https:\/\/andreas-hubel.de\/?p=380"},"modified":"2026-09-21T01:11:57","modified_gmt":"2026-09-20T23:11:57","slug":"voctosocial","status":"publish","type":"post","link":"https:\/\/andreas-hubel.de\/en\/voctosocial\/","title":{"rendered":"media.ccc.de on the Fediverse"},"content":{"rendered":"<p>A week ago, I was at this year&#8217;s <a href=\"https:\/\/berlinfedi.day\">Berlin FediDay<\/a> and, as part of the <a href=\"https:\/\/ctalx.c-base.org\/fediday-2026\/talk\/AX9DLF\/\">Barcamp<\/a> there, offered a project update on the topic of <strong>media.ccc.de on the Fediverse<\/strong>. Someone was kind enough to take notes during the session, so here&#8217;s a lightly edited write-up:<\/p>\n<p>&nbsp;<\/p>\n<p>The software behind media.ccc.de is called <strong>voctoweb<\/strong>; the planning and analysis for this project can be found, among other places, in the following issues:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/852\">#852 Fediverse EPIC<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/735\">#735 Define ActivityPub representation of a talk\/event\/lecture<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/853\">#853 Decide on an ActivityPub architecture<\/a><\/li>\n<\/ul>\n<h2>Goal<\/h2>\n<p>ActivityPub is being implemented as a inherent part of media.ccc.de, rather than migrating to PeerTube. Even so, it should also become usable with PeerTube and other Fediverse apps.<\/p>\n<p>PeerTube&#8217;s torrent component doesn&#8217;t play a big role for media.ccc.de, since traffic demand is generally covered by dedicated mirrors and sponsorship and isn&#8217;t the bottleneck. The vision is for media.ccc.de to act as a bridge for conferences with <a href=\"https:\/\/c3voc.de\/wiki\/schedule#schedule2\">schedule.xml\/json<\/a> into the Fediverse.<\/p>\n<p><a href=\"https:\/\/c3voc.de\/wiki\/software:voctoweb#deployments\">cdn.media.ccc.de uses MirrorBrain<\/a>, comparable to the mirror networks used by Linux distributions. Requests are redirected to a nearby mirror, and checksums allow verification of the downloaded file. The mirrors are listed, along with additional information, on the <a href=\"https:\/\/media.ccc.de\/about.html#privacy\">about page<\/a>.<\/p>\n<p><!--more--><\/p>\n<h2>Current state of implementation<\/h2>\n<p>The focus so far has been on metadata: People are now stored as their own entities in the database \u2014 no longer just as a string array \u2014 which will enable better search-ability and linking. For each person there&#8217;s a primary GUID plus alias GUIDs, in case the same person shows up elsewhere under a different identity.<\/p>\n<p>The current plan for the next step is a separate login for speakers on media.ccc.de \u2014 but entirely without a password: you enter an email address or Fediverse handle, then log in via OIDC\/OAuth2 with your instance\/IdP, or receive an email with a one-time login link. Instead of having to email the VOC, speakers would then be able to edit their own metadata \u2014 for example, merging different GUIDs, adding a Fediverse account, or editing their display name.<\/p>\n<p>The voctoweb codebase currently runs on Rails 7.2 \u2014 some tasks, such as evaluating what the <a href=\"https:\/\/github.com\/mastodon\/fediverse_auxiliary_service_provider_specifications\">Fediverse Auxiliary Service Provider (FASP)<\/a> spec could bring us, which we could test with the <a href=\"https:\/\/github.com\/manyfold3d\/fasp_client\">fasp_client<\/a> Rails plugin, are blocked on the upgrade to Rails 8.0 \u2014 <a href=\"https:\/\/github.com\/voc\/voctoweb\/pull\/938\">which is already fairly far along, though<\/a>.<\/p>\n<h2>Data model \u2013 What does the ActivityPub representation look like? (<a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/735\">#735<\/a>)<\/h2>\n<p>Until now, voctoweb has primarily had Conference + Event.<\/p>\n<p>There&#8217;s an idea to shift these two entities, in the externally exposed data model, to a Grouping + Item structure based on Schema.org types:<\/p>\n<ul>\n<li>A Grouping could then be a conference, a talk series at a (hacker)space (OpenChaos, Datengarten, Hackfriday, etc.), a conference series (as an umbrella over the individual editions of a given conference), \u2026<\/li>\n<li>Items would then be talks, workshops, documentaries, films, \u2026<\/li>\n<\/ul>\n<p>It&#8217;s still partly an open question who\/how this new metadata would be maintained &#8220;editorially&#8221;: the events\/items and the collection&#8217;s base metadata can be imported from schedule.xml or schedule2.json for all CCC conferences of the last 10\u201320 years, but the structural data is manual work. The current idea is to represent this via a <a href=\"https:\/\/forgejo.c3voc.de\/media\/meta\">git repo in Terraform<\/a>, in the hope that this would let part of the maintenance effort be crowdsourced to the community.<\/p>\n<p>The old REST API naturally keeps its existing semantics, so that existing clients of that API continue to work.<\/p>\n<h2>Architecture \/ implementation path (<a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/853\">#853<\/a>)<\/h2>\n<p>Broadly speaking, there are two main paths for implementation: either you integrate the ActivityPub server fully into your web app \u2014 for example, in Rails, by building fedipub in as an engine directly inside voctoweb \u2014 or you delegate notification\/subscription management to a separate service, as Ghost did for its ActivityPub service.<\/p>\n<p>Currently we&#8217;re going the second route, setting up our own dedicated service under social.media.ccc.de, while the metadata for the individual entities should still come from voctoweb itself, without being permanently duplicated \u2014 see the example excerpt from <a href=\"https:\/\/github.com\/voc\/voctoweb\/issues\/735\">#735<\/a>:<\/p>\n<pre><code>{\r\n  \"type\": \"Video\",\r\n  \"id\": \"https:\/\/media.ccc.de\/v\/37c3-12142-breaking_drm_in_polish_trains\",\r\n  \"uuid\": \"68160267-a6a5-4a41-8a51-d8735c8aa338\",\r\n  \"to\": [\"https:\/\/www.w3.org\/ns\/activitystreams#Public\"],\r\n  \"cc\": [\"https:\/\/social.media.ccc.de\/accounts\/37c3\/followers\"],\r\n\r\n  \"name\": \"Breaking \\\"DRM\\\" in Polish trains\",\r\n  \"attributedTo\": [\r\n    {\"type\": \"Person\", \"name\": \"Redford\", \"id\": \"acct:redford@dragonsector.pl\"},\r\n    {\"type\": \"Person\", \"name\": \"q3k\", \"id\": \"acct:q3k@hackerspace.pl\"},\r\n    {\"type\": \"Person\", \"name\": \"MrTick\"},\r\n    {\"type\": \"Group\",  \"name\": \"Dragon Sector\", \"id\": \"https:\/\/dragonsector.pl\"}\r\n  ],\r\n  \"mediaType\": \"text\/markdown\",\r\n  \"content\": \"We've all been there: the trains you're servicing for a customer suddenly brick themselves and the manufacturer claims that's because you've interfered with a security system.\\n\\nThis talk will tell the story of a series of Polish EMUs (Electric Multiple Unit) that all refused to move a few days after arriving at an \\u201cunauthorized\\u201d service company. We'll go over how a train control system actually works, how we reverse-engineered one and what sort of magical \\u201csecurity\\u201d systems we actually found inside of it.\\n\\nReality sometimes is stranger than the wildest CTF task. Reality sometimes is running `unlock.py` on a dozen trains.\\n\\nThe talk will be a mix of technical and non-technical aspects of analysis which should be understandable for anyone with a technical background. We\\u2019ll briefly explain how modern EMUs look like inside, how the Train Control & Monitoring System works, and how to analyze TriCore machine code.\",\r\n  \"duration\": \"PT3705S\",\r\n  \u2026\r\n}\r\n<\/code><\/pre>\n<h2>Further points &amp; discussions during the session<\/h2>\n<h4>How can interoperability be meaningfully tested before rolling new features out to production?<\/h4>\n<p>One way to inspect and debug ActivityPub objects that was mentioned was <a href=\"https:\/\/browser.pub\/\">BrowserPub<\/a>. What I&#8217;d like most here is to be able to test new federation features of voctoweb in a sensible, reproducible, automated way \u2014 i.e., checking how a Mastodon\/PeerTube\/etc. server or client actually processes or displays the entities.<\/p>\n<h4>What are established best practices for testing federation locally or in isolation?<\/h4>\n<p>Another concern is the risk of &#8220;burning&#8221; a domain or instance for further tests due to faulty federation requests or states. When using Fedify, this generally shouldn&#8217;t be much of a problem. More critical, however, could be error states such as deadlocks or inconsistent states, where it becomes difficult to cleanly reset back to the original status. This seems especially relevant when a two-sided state develops between the participating instances. With purely one-sided interactions, resetting or repeating tests should be considerably simpler.<\/p>\n<p>Afterward, the idea came up of using the test instances at <a href=\"https:\/\/fedihub_org.codeberg.page\/\">Fedihub<\/a>\/<a href=\"https:\/\/anoxinon.de\">Anoxinon<\/a> for such tests \u2014 some VOC members are already active there anyway.<\/p>\n<p>If you&#8217;re interested in following the project&#8217;s progress, feel free to follow <a href=\"https:\/\/chaos.social\/@saerdnaer\">@saerdnaer@chaos.social<\/a> or <a href=\"https:\/\/chaos.social\/@c3voc\">@c3voc@chaos.social<\/a>, or reach out to me or in <a href=\"https:\/\/matrix.to\/#\/#voc-media:matrix.as62269.net\">#voc-media<\/a> if you&#8217;d like to get involved in the project \u2014 whether as a developer, tester, etc.<\/p>","protected":false},"excerpt":{"rendered":"<p>Sorry, this entry is only available in Deutsch.<\/p>\n","protected":false},"author":1,"featured_media":387,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"federated","footnotes":"","atmosphere_disabled":false,"atmosphere_custom_text":"","atmosphere_reply_restriction":[]},"categories":[20,19],"tags":[],"class_list":["post-380","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c3voc","category-fediverse"],"_links":{"self":[{"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/posts\/380","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/comments?post=380"}],"version-history":[{"count":9,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/posts\/380\/revisions"}],"predecessor-version":[{"id":392,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/posts\/380\/revisions\/392"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/media\/387"}],"wp:attachment":[{"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/media?parent=380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/categories?post=380"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andreas-hubel.de\/en\/wp-json\/wp\/v2\/tags?post=380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}