78 lines
6.7 KiB
HTML
78 lines
6.7 KiB
HTML
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="UTF-8">
|
|||
|
<meta name="viewport" content="width=device-width">
|
|||
|
<!--<link rel="icon" type="image/svg+xml" href="/favicon.svg" />-->
|
|||
|
<meta name="generator" content="Astro v2.10.7">
|
|||
|
<meta name="description" content="{frontmatter.description}">
|
|||
|
<meta name="keywords" content="nothing crypto free software libre self host {frontmatter.keys}">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<link rel="icon" href="/nothingrun-favicon-whiteonblack.png" type="image/png">
|
|||
|
|
|||
|
<title>Restoration of Synapse after disappearing 1 year of database history</title>
|
|||
|
<link rel="stylesheet" href="/_astro/contact.f052f577.css" /></head>
|
|||
|
<body>
|
|||
|
<div class="header astro-HPNW4VWY">
|
|||
|
<a href="/" class="astro-HPNW4VWY">~/</a>
|
|||
|
<a href="/contact" class="astro-HPNW4VWY">Contact</a>
|
|||
|
<a href="https://uptime.nothing.run" class="astro-HPNW4VWY">Uptime</a>
|
|||
|
<a href="/news" class="astro-HPNW4VWY">News</a>
|
|||
|
<a href="/notes" class="astro-HPNW4VWY">Notes</a>
|
|||
|
<a href="/donate" class="astro-HPNW4VWY">Donate :3</a>
|
|||
|
</div>
|
|||
|
|
|||
|
<h1>Restoration of Synapse after disappearing 1 year of database history</h1>
|
|||
|
|
|||
|
<div class="article"><h2 id="introduction">Introduction</h2><p>In July 2025, my PostgreSQL had broken, so I needed to restore it from my 1-y.o. backup. I was thinking about what to do, and my friend sent me <a href="https://blog.erethon.com/blog/2023/06/21/what-happens-when-a-matrix-server-disappears/">this</a> article, so we understood what to do!</p><p>For example, there is a room called #example:example.org (roomid !example:example.org), whose member was @user:example.net.
|
|||
|
The problem is that every server knows @user:example.net is in the room #example:example.org. But our server doesn’t! So that is what we should aim at solving the problem.</p><h2 id="architecture">Architecture</h2><p>We get 2 types of error messages:</p><ul>
|
|||
|
<li><code>synapse.handlers.receipts: [PUT-...] Ignoring receipt for room '!example:example.org' from server example.org as we're not in the room</code> (there is the same error message, but when you get a typing event from an unknown room)</li>
|
|||
|
<li><code>synapse.federation.federation_server: [PUT-...] Ignoring PDU for unknown room_id: !example:example.org</code></li>
|
|||
|
</ul><p>We can read the journal and parse the error message (I use a bash script to do that).
|
|||
|
Okay, we have a room id! In the given article, the author is the only user of their server, so they can just send <a href="https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3joinroomidoralias">POST /_matrix/client/v3/join/!example:example.org</a> request, and everything will be good.
|
|||
|
But my server has multiple users, so I can’t use the easiest way. We need to get information about membership (so we need to get state).</p><p>As we are admins of our servers, we have their signing keys.
|
|||
|
We will need them because we are going to get state via Federation API requests.
|
|||
|
How? There are different ways to do that.
|
|||
|
However, all of them require at least 1 event id, so firstly we need to do <a href="https://spec.matrix.org/v1.15/server-server-api/#get_matrixfederationv1timestamp_to_eventroomid">GET /_matrix/federation/v1/timestamp_to_event</a>.
|
|||
|
Determining request parameters (?dir as direction (b[ackward] or f[orward]) and &ts as timestamp in Unix time format in milliseconds), we have just got either the last or the first event id! In my case, I chose the way of getting the last event, so then I’ll have to make <a href="https://spec.matrix.org/v1.15/server-server-api/#get_matrixfederationv1stateroomid">GET /_matrix/federation/v1/state/!example:example.org?event_id=$event_id</a>, and I will get the actual state.
|
|||
|
Of course, both of the requests, as I said, should be signed using your server’s key (<a href="https://spec.matrix.org/v1.15/server-server-api/#signing-events">how to sign events</a>).</p><br/><p>(There is no support of timestamp_to_event in Conduit, so it would be a good idea to make support of requesting different servers)</p><p>After we receive the state, we need to parse it, but I think this can’t make a difficulty.
|
|||
|
As a result, we have a list of our users that were in the given room, like [“@user:example.net”, “@anotheruser:example.net”, “@exampleuser:example.net”].
|
|||
|
Then, the simplest way is to get temporary user’s auth token via <a href="https://github.com/matrix-org/synapse/blob/develop/docs/admin_api/user_admin_api.md#login-as-a-user">POST /_synapse/admin/v1/users/user_id/login</a> and make <a href="https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3joinroomidoralias">POST /_matrix/client/v3/join/!example:example.org</a> from the name of the user using their token.
|
|||
|
The problem is solved!</p><h2 id="external-links">External links</h2><ul>
|
|||
|
<li><a href="https://blog.erethon.com/blog/2023/06/21/what-happens-when-a-matrix-server-disappears/">Article that gave me the idea</a></li>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/server-server-api/">Matrix Federation API docs</a>
|
|||
|
<ul>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/server-server-api/#signing-events">How to sign Federation API requests</a></li>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/server-server-api/#get_matrixfederationv1stateroomid">GET /_matrix/federation/v1/state/!example:example.org?event_id=$event_id</a></li>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/server-server-api/#get_matrixfederationv1timestamp_to_eventroomid">GET /_matrix/federation/v1/timestamp_to_event</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/server-server-api/">Matrix Client API docs</a>
|
|||
|
<ul>
|
|||
|
<li><a href="https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3joinroomidoralias">POST /_matrix/client/v3/join/!example:example.org</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="https://github.com/matrix-org/synapse/blob/develop/docs/admin_api/user_admin_api.md#login-as-a-user">Admin API POST /_synapse/admin/v1/users/user_id/login</a></li>
|
|||
|
</ul></div>
|
|||
|
<div id="footer">
|
|||
|
<main>
|
|||
|
<pre> .--.
|
|||
|
." o \__
|
|||
|
_.-" ,( `
|
|||
|
_.-" ,;;|
|
|||
|
_.-=" _," ,,;;;'
|
|||
|
.-"`_.-"``-..,,;;;;:'
|
|||
|
`"'` `\`\
|
|||
|
/^\\\
|
|||
|
</pre>
|
|||
|
</main>
|
|||
|
<aside>
|
|||
|
<b>Made with ♥</b> by Thary<br>
|
|||
|
<!-- Website sources are available on <a href="https://git.vector1.dev/thary/website">Gitea</a>!<br> -->
|
|||
|
<!-- All content is in Public domain and licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a><br> -->
|
|||
|
Logo is created by <a href="https://houl.floof.company/">Houl</a><br>
|
|||
|
ASCII arts are taken from <a href="https://web.archive.org/web/20010420182629/http://www.geocities.com/spunk1111/indexjava.htm">this website</a>
|
|||
|
</aside>
|
|||
|
</div>
|
|||
|
|
|||
|
</body></html>
|