Authentifizierte ICS-Feeds für private Kalenderereignisse

Der öffentliche ICS-Export wurde kürzlich über

GET /discourse-post-event/events.ics wieder eingeführt, was eine großartige Verbesserung nach der Arbeit in

Re-Add full ICS export darstellt.

Derzeit scheint dieser Endpunkt auf Ereignisse beschränkt zu sein, die für anonyme Benutzer sichtbar sind. Infolgedessen können Ereignisse in privaten Kategorien oder Kategorien, die von der Standardgruppe everyone ausgeschlossen sind, nicht in externen Kalenderclients (z. B. Google Kalender, Outlook) abonniert werden.

Wäre es möglich, den authentifizierten Zugriff auf diesen Endpunkt zu unterstützen, ähnlich wie Discourse private RSS/Atom-Feeds behandelt (zum Beispiel über ein pro Benutzer generiertes Token oder einen schreibgeschützten API-Schlüssel)?

Dies würde keine Berechtigungsregeln ändern – es würde Kalenderclients lediglich ermöglichen, auf Ereignisse zuzugreifen, die der Benutzer bereits sehen darf.

Ich stelle dies als separate, eingegrenzte Anfrage nach der Wiedereinführung des öffentlichen ICS-Feeds, wie zuvor vorgeschlagen.

1 „Gefällt mir“

Nachdem ich den Code eingehend geprüft hatte, habe ich einen sehr einfachen Proxy programmiert, der verschiedene Hürden bei der Erstellung eines Benutzer-API-Schlüssels und dessen Übergabe an die API bewältigt; er generiert auch einen Link, den die Benutzer in ihre Kalenderanwendungen einfügen müssen:

Hoffentlich wird all dies eines Tages in den Discourse-Code übernommen, und es wird nicht mehr benötigt – in der Zwischenzeit teile ich dies in der Hoffnung, anderen das Leben leichter zu machen.

Ich habe das diese Woche früher in diesem PR hinzugefügt. Die Ergonomie der Generierung von Benutzer-API-Schlüsseln ist jedoch für nicht-technische Benutzer nicht ideal. Um dies nahtlos zu gestalten, folge ich mit:

Was versucht, dies so benutzerfreundlich wie möglich zu gestalten.

1 „Gefällt mir“

Ich habe diese Funktion gerade zusammengeführt, kannst du sie bitte ausprobieren, @Ethsim2?

1 „Gefällt mir“

Danke – ich kann bestätigen, dass der authentifizierte Feed auf meiner Seite jetzt ordnungsgemäß generiert wird.

Das verbleibende Problem scheint die Client-Kompatibilität zu sein: Weder Google Kalender noch Outlook scheinen direkt ein authentifiziertes ICS-Feed in dieser Form abonnieren zu wollen. Daher plane ich vorerst, dies zu umgehen, indem ich einen Nginx Reverse Proxy auf Host-Ebene vor meiner Ein-Container-Discourse-Installation setze und dort stattdessen eine einfache .ics-Datei bereitstelle.

Da ich das Standard-Ein-Container-Setup verwende, bedeutet dies meiner Meinung nach, die Ports 80/443 vom Container zu entfernen, Discourse dazu zu bringen, auf einem internen hohen Port zu lauschen, und dann den Host-Nginx den Forum-Verkehr zu proxen und zusätzlich einen statischen Kalenderfeed-Pfad bereitzustellen.

Grob gesagt sind die Befehle, die ich voraussichtlich verwenden werde:

# 1. Host nginx + certbot installieren
sudo apt update
sudo apt install -y nginx snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

# 2. Den Discourse-Container stoppen, damit die Ports 80/443 freigegeben werden können
cd /var/discourse
sudo ./launcher stop app

# 3. Die Container-Konfiguration bearbeiten, damit Discourse nicht mehr direkt an 80/443 bindet
sudo nano /var/discourse/containers/app.yml

Dann in app.yml den expose-Abschnitt ändern von:

expose:
  - "80:80"
  - "443:443"

auf etwas wie:

expose:
  - "127.0.0.1:8080:80"

und, falls vorhanden, die Container-SSL-/Let’s Encrypt-Vorlagen entfernen, damit TLS am Host-Reverse-Proxy beendet wird.

Dann neu erstellen:

cd /var/discourse
sudo ./launcher rebuild app

Anschließend eine Nginx-Konfiguration auf Host-Ebene erstellen, z. B.:

sudo nano /etc/nginx/sites-available/discourse

mit etwas in der Art von:

server {
    listen 80;
    listen [::]:80;
    server_name forum.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /private-calendar/ethan.ics {
        alias /var/www/private-calendar/ethan.ics;
        default_type text/calendar;
        add_header Content-Type "text/calendar; charset=utf-8";
    }
}

Aktivieren und neu laden:

sudo mkdir -p /var/www/private-calendar
sudo mkdir -p /var/www/certbot
sudo ln -s /etc/nginx/sites-available/discourse /etc/nginx/sites-enabled/discourse
sudo nginx -t
sudo systemctl reload nginx

Dann ein Let’s Encrypt-Zertifikat mit Certbot beziehen und es die Nginx-Konfiguration aktualisieren lassen:

sudo certbot --nginx -d forum.example.com
sudo nginx -t
sudo systemctl reload nginx

Danach wird die Nginx-Konfiguration typischerweise auch einen HTTPS-Serverblock enthalten, z. B.:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name forum.example.com;

    ssl_certificate /etc/letsencrypt/live/forum.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/forum.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /private-calendar/ethan.ics {
        alias /var/www/private-calendar/ethan.ics;
        default_type text/calendar;
        add_header Content-Type "text/calendar; charset=utf-8";
    }
}

Zu diesem Zeitpunkt kann ich ein Skript/einen Timer auf dem Host verwenden, um den authentifizierten Discourse ICS abzurufen und in folgende Datei zu schreiben:

/var/www/private-calendar/ethan.ics

worauf Google Kalender/Outlook dann als normale öffentliche ICS-URL abonnieren können.

Aus meiner Sicht ist die Discourse-Seite also jetzt gelöst; die verbleibende praktische Lücke ist hauptsächlich, dass große Kalenderclients authentifizierte ICS-Feeds nicht besonders gut verarbeiten, weshalb ich vorerst auf einen öffentlichen Proxy-/Static-File-Ansatz zurückgreife.

Ich gehe auch davon aus, dass Certbot der einfachste Weg ist, da es die Ausstellung/Erneuerung von Let’s Encrypt direkt gegen den Host Nginx verwalten kann. Ich könnte auch acme.sh verwenden, aber mein Eindruck ist, dass dies bei diesem speziellen Setup eher eine manuelle Wahl wäre als der direkteste Weg.

Moment mal, was?

Ich verwende es einwandfrei mit meinem Google Kalender, ebenso wie einige meiner Kollegen.

Welcher Teil davon ist mit dem Google Kalender inkompatibel!?

Ah, danke, das hilft bei der Eingrenzung.

Auf meiner Seite akzeptiert Google Kalender die Abonnement-URL (über „Über URL hinzufügen“), aber das Verhalten, das ich beobachte, ist:

  • der Kalender wird erfolgreich hinzugefügt
  • er zeigt jedoch überhaupt keine Ereignisse an

Es ist also kein Fall, dass die URL abgelehnt wird – es ist eher so, dass der Feed aus Googles Sicht leer erscheint.

Da die rohe ICS-Datei eindeutig VEVENT-Einträge enthält (z. B. mit UID, DTSTART, SUMMARY usw.), lässt dies vermuten, dass es sich um etwas wie Folgendes handeln könnte:

  • Google filtert vergangene Ereignisse heraus (die meisten meiner Testdaten sind historisch)
  • oder etwas an der Art und Weise, wie der Feed interpretiert wird (z. B. Zeitbereich, Caching oder Header)

Lassen Sie mich wissen, ob es etwas Bestimmtes gibt, das Sie im Feed selbst überprüfen möchten.

2 „Gefällt mir“

Können Sie /logs auf Fehler überprüfen? Ich habe gerade einen behoben, bei dem alte wiederkehrende Ereignisse dazu führten, dass der Feed fehlschlug.

Wenn es derselbe Fehler war, müssen Sie aktualisieren.

Ich müsste weiter zurück als 19:00 Uhr graben, da es viele Warnungen/Fehler im Zusammenhang mit Discourse AI – Token-Limit gibt.

1 „Gefällt mir“
1 „Gefällt mir“