source: Klonkt/src/services/hub-invite.js

main
Last change on this file was 31680c3, checked in by Robin <roboburr@…>, 5 hours ago

[Add to HUB] on the Connect page — the click is the owner's yes

Putting a klonkt on the Klonkt Hub means the hub sends a Follow. With the
owner gate on (the default) that Follow then waits for the owner — the same
person who just asked for it. Without this they would sign up on the hub and
then have to approve their own sign-up on /connect.

The button POSTs to /connect/add-to-hub, which records a one-day invitation
and redirects to the hub's sign-up form with the site's handle filled in
(?add=). A Follow from the hub's host, signed by the hub itself, passes the
owner gate while that invitation holds. It is not used up on the first
Follow: a hub that re-sends after a timeout would otherwise land in the queue
for something already decided.

Narrow on purpose: only the hub's host, only signed by it, only for a day.
Anyone else still waits for the owner, and a WARD's guardians still decide —
their gate sits before this one and this path never reaches it.

If a request from the hub is already waiting (someone signed the klonkt up
earlier), the click is exactly the yes it waits for: it is accepted on the
spot and the button goes to the channel on the hub instead of the form. Once
the hub follows, /connect shows a confirmation instead of the button. Hidden
after a move, where the outgoing side is locked.

KLONKT_HUB_URL lets a self-hoster point the button at another hub; default
​https://hub.klonkt.com.

Co-Authored-By: Claude Opus 5.5 <noreply@…>

  • Property mode set to 100644
File size: 2.4 KB
RevLine 
[31680c3]1/**
2 * [Add to HUB] — een klonkt zelf op de Klonkt Hub zetten (Robin, 30-9).
3 *
4 * WAAROM DIT MEER IS DAN EEN LINK. Aanmelden op de hub betekent: de hub
5 * stuurt een Follow. Met de eigenaarspoort aan (standaard) wacht die Follow
6 * dan op de eigenaar -- dezelfde persoon die net op de knop drukte. Zonder dit
7 * stuk zou die dus eerst zijn klonkt aanmelden en daarna zijn eigen aanmelding
8 * moeten goedkeuren op /connect.
9 *
10 * De klik IS de toestemming. Hij geldt kort (een dag), alleen voor een Follow
11 * van de host van de hub, en alleen als die Follow is ondertekend door de hub
12 * zelf. De poort blijft verder precies wat hij was: niemand anders komt er
13 * zonder ja door, en bij een WARD beslissen nog steeds de guardians -- die
14 * poort staat in ap-inbox VOOR deze, en daar komt dit stuk nooit langs.
15 *
16 * De uitnodiging wordt niet opgebruikt bij de eerste Follow maar loopt af. Een
17 * hub die zijn Follow opnieuw stuurt (na een time-out) krijgt anders alsnog
18 * een wachtend verzoek voor iets dat al beslist was.
19 */
20import db from '../config/database.js';
21
22const GELDIG_MS = 24 * 3600 * 1000;
23
24/** De hub waar de knop naartoe wijst. Zelfhosters kunnen een andere kiezen. */
25export function hubUrl() {
26 return String(process.env.KLONKT_HUB_URL || 'https://hub.klonkt.com').replace(/\/+$/, '');
27}
28
29function hubHost() {
30 try { return new URL(hubUrl()).host.toLowerCase(); } catch { return ''; }
31}
32
33function hostOf(uri) {
34 try { return new URL(uri).host.toLowerCase(); } catch { return ''; }
35}
36
37/** Komt dit actor-adres van de hub? */
38export const isHubActor = (uri) => !!uri && hostOf(uri) === hubHost();
39
40/** De eigenaar zegt ja, vooruit: de volgende dag mag een Follow van de hub door. */
41export function invite(siteId) {
42 db.prepare('UPDATE sites SET hub_invite_until = ? WHERE id = ?').run(Date.now() + GELDIG_MS, siteId);
43}
44
45/** Heeft de eigenaar van `slug` de hub uitgenodigd, en is dat nog geldig? */
46export function isInvited(slug, actorUri) {
47 if (!isHubActor(actorUri)) return false;
48 const r = db.prepare('SELECT hub_invite_until FROM sites WHERE slug = ?').get(slug);
49 return !!(r && r.hub_invite_until && r.hub_invite_until > Date.now());
50}
51
52/** Volgt de hub deze klonkt al? Dan hoort er geen knop maar een bevestiging. */
53export function onHub(slug) {
54 const rows = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ?').all(slug);
55 return rows.some((r) => isHubActor(r.actor_uri));
56}
Note: See TracBrowser for help on using the repository browser.