Flux ICS authentifiés pour les événements de calendrier privés

L’exportation ICS publique a été récemment réintroduite via

GET /discourse-post-event/events.ics, ce qui constitue une excellente amélioration suite au travail réalisé dans

Réajouter l’exportation ICS complète.

Actuellement, ce point de terminaison semble limité aux événements visibles par les utilisateurs anonymes. Par conséquent, les événements dans les catégories privées ou les catégories restreintes au groupe par défaut everyone ne peuvent pas être abonnés dans les clients de calendrier externes (par exemple, Google Calendar, Outlook).

Serait-il possible de prendre en charge l’accès authentifié à ce point de terminaison, similaire à la façon dont Discourse gère les flux RSS/Atom privés (par exemple, via un jeton par utilisateur ou une clé API de lecture seule) ?

Cela ne modifierait aucune règle d’autorisation - cela permettrait simplement aux clients de calendrier d’accéder aux événements que l’utilisateur est déjà autorisé à voir.

Je soulève ceci comme une demande distincte et délimitée suite à la réintroduction du flux ICS public, comme suggéré précédemment.

1 « J'aime »

Après avoir examiné attentivement le code, j’ai fini par coder un proxy très simple qui gère divers obstacles nécessaires pour créer une clé d’API utilisateur et la transmettre à l’API ; il génère également un lien que les utilisateurs doivent coller dans leurs applications de calendrier :

J’espère que tout cela fera un jour partie du code de Discourse et ne sera plus nécessaire - en attendant, je partage ceci dans l’espoir de faciliter la vie des autres.

J’ai ajouté cela plus tôt cette semaine dans cette Pull Request. Cependant, l’ergonomie de la génération de clés API utilisateur n’est pas idéale pour les utilisateurs non techniques. Pour que cela soit transparent, je fais un suivi avec :

Ce qui essaie de rendre cela aussi convivial que possible

1 « J'aime »

Je viens de fusionner cette fonctionnalité, pouvez-vous essayer @Ethsim2 ?

1 « J'aime »

Merci - je peux confirmer que le flux authentifié lui-même est maintenant généré correctement de mon côté.
Le problème restant semble être la compatibilité du client : ni Google Calendar ni Outlook ne semblent apprécier de s’abonner directement à un flux ICS authentifié sous cette forme. Pour l’instant, je prévois donc de contourner cela en plaçant un proxy inverse Nginx au niveau de l’hôte devant mon installation Discourse dans un conteneur unique et en servant à la place un fichier .ics simple.

Étant sur la configuration standard à conteneur unique, je pense que cela signifie retirer les ports 80/443 du conteneur, faire en sorte que Discourse écoute sur un port interne élevé, puis demander à Nginx hôte de transférer (proxy) le forum et également de servir un chemin de fichier de calendrier statique.

En gros, les commandes que je prévois d’utiliser sont :

# 1. Installer Nginx hôte + certbot
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. Arrêter le conteneur Discourse afin que les ports 80/443 puissent être libérés
cd /var/discourse
sudo ./launcher stop app

# 3. Éditer la configuration du conteneur pour que Discourse ne se lie plus directement à 80/443
sudo nano /var/discourse/containers/app.yml

Ensuite, dans app.yml, changer la section expose de :

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

à quelque chose comme :

expose:
  - "127.0.0.1:8080:80"

et, si elle est présente, supprimer les modèles SSL conteneur / Let’s Encrypt afin que la terminaison TLS soit effectuée sur le proxy inverse de l’hôte à la place.

Puis reconstruire :

cd /var/discourse
sudo ./launcher rebuild app

Ensuite, créer un site Nginx au niveau de l’hôte tel que :

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

avec quelque chose comme :

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";
    }
}

L’activer et recharger :

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

Ensuite, obtenir un certificat Let’s Encrypt avec Certbot et le laisser mettre à jour la configuration Nginx :

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

Après cela, la configuration Nginx inclura généralement également un bloc serveur HTTPS, par exemple :

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";
    }
}

À ce stade, je pourrai utiliser un script/minuteur sur l’hôte pour récupérer l’ICS Discourse authentifié et écrire :

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

auquel Google Calendar / Outlook pourront s’abonner en tant qu’URL ICS publique normale.
Donc, de mon point de vue, le côté Discourse semble résolu maintenant ; le fossé pratique restant est principalement que les principaux clients de calendrier ne gèrent pas particulièrement bien les flux ICS authentifiés, c’est pourquoi je reviens à une approche proxy public/fichier statique pour l’instant.

Je suppose également que Certbot est la voie la plus simple ici, car il peut gérer l’émission/le renouvellement de Let’s Encrypt directement contre Nginx hôte. Je pourrais aussi utiliser acme.sh, mais mon impression est que ce serait plus un choix manuel qu’une voie la plus directe pour cette configuration spécifique.

Attends, quoi ?

Je l’utilise avec mon Google Agenda sans problème, ainsi que certains de mes collègues.

Quelle partie est incompatible avec Google Agenda !?

Ah, merci, cela aide à restreindre le champ.

De mon côté, Google Agenda accepte bien l’URL d’abonnement (via “À partir de l’URL”), mais le comportement que j’observe est le suivant :

  • le calendrier est ajouté avec succès
  • cependant, il n’affiche aucun événement

Ce n’est donc pas un cas où l’URL est rejetée - c’est plutôt que le flux semble vide du point de vue de Google.

Étant donné que l’ICS brut contient clairement des entrées VEVENT (par exemple avec UID, DTSTART, SUMMARY, etc.), cela me fait penser que cela pourrait être quelque chose comme :

  • Google filtre les événements passés (la plupart de mes données de test sont historiques)
  • ou quelque chose concernant la manière dont le flux est interprété (par exemple, la plage de temps, la mise en cache ou les en-têtes)

Faites-moi savoir s’il y a quelque chose de spécifique que vous aimeriez que je vérifie dans le flux lui-même.

2 « J'aime »

Pouvez-vous vérifier les journaux (/logs) pour les erreurs ? Je viens d’en corriger une où les anciens événements récurrents provoquaient l’échec du flux.

S’il s’agissait de la même erreur, vous devez mettre à jour.

Je devrais remonter plus tôt que 19 heures, car il y a de nombreux avertissements/erreurs liés à Discourse AI - limite de jetons

1 « J'aime »
1 « J'aime »