Feeds ICS autenticados para eventos de calendário privados

A exportação pública do ICS foi recentemente reintroduzida através de

GET /discourse-post-event/events.ics, o que é uma ótima melhoria após o trabalho em

Re-Add full ICS export.

No momento, este endpoint parece estar limitado a eventos visíveis para usuários anônimos. Como resultado, eventos em categorias privadas ou categorias restritas do grupo padrão everyone não podem ser subscritos em clientes de calendário externos (por exemplo, Google Calendar, Outlook).

Seria viável suportar acesso autenticado a este endpoint, semelhante à forma como o Discourse lida com feeds RSS/Atom privados (por exemplo, através de um token por usuário ou chave de API somente leitura)?

Isso não alteraria nenhuma regra de permissão - simplesmente permitiria que os clientes de calendário acessassem os eventos que o usuário já está autorizado a ver.

Estou levantando isso como uma solicitação separada e com escopo definido, após a reintrodução do feed ICS público, conforme sugerido anteriormente.

1 curtida

Depois de analisar o código, acabei codificando um proxy muito simples que lida com vários obstáculos necessários para criar uma Chave de API de Usuário e passá-la para a API; ele também gera um link que os usuários precisam colar em seus aplicativos de calendário:

Espero que tudo isso um dia chegue ao código do Discourse e não seja mais necessário - enquanto isso, estou compartilhando isso na esperança de facilitar a vida de outros.

Eu adicionei isso no início desta semana neste PR. No entanto, a usabilidade de gerar Chaves de API de Usuário não é ótima para usuários não técnicos. Para tornar isso contínuo, estou dando seguimento com:

O que tenta tornar isso o mais amigável possível

1 curtida

Acabei de mesclar este recurso, você pode experimentá-lo @Ethsim2?

1 curtida

Obrigado - posso confirmar que o feed autenticado em si agora está sendo gerado corretamente do meu lado.

O problema restante parece ser a compatibilidade do cliente: nem o Google Calendar nem o Outlook parecem satisfeitos em se inscrever diretamente em um feed ICS autenticado desta forma, então, por enquanto, planejo contorná-lo colocando um proxy reverso Nginx em nível de host na frente da minha instalação Discourse de contêiner único e servindo um arquivo .ics simples lá em vez disso.

Como estou na configuração padrão de contêiner único, acho que isso significa mover as portas 80/443 para fora do contêiner, fazer o Discourse escutar em uma porta alta interna e, em seguida, fazer o Nginx do host fazer proxy do fórum e também servir um caminho de arquivo de calendário estático.

Aproximadamente, os comandos que espero usar são:

# 1. Instalar o Nginx do host + 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. Parar o contêiner do Discourse para que as portas 80/443 possam ser liberadas
cd /var/discourse
sudo ./launcher stop app

# 3. Editar a configuração do contêiner para que o Discourse não se vincule mais diretamente a 80/443
sudo nano /var/discourse/containers/app.yml

Em seguida, em app.yml, altere a seção expose de:

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

Para algo como:

expose:
  - "127.0.0.1:8080:80"

E, se presente, remova os modelos de SSL/Let’s Encrypt do contêiner para que o TLS seja encerrado no proxy reverso do host em vez disso.

Em seguida, reconstrua:

cd /var/discourse
sudo ./launcher rebuild app

Em seguida, crie um site de nível de host, como:

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

Com algo como:

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

Habilite-o e recarregue:

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

Em seguida, obtenha um certificado Let’s Encrypt com Certbot e deixe-o atualizar a configuração do Nginx:

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

Depois disso, a configuração do Nginx normalmente incluirá um bloco de servidor HTTPS também, por exemplo:

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

Nesse ponto, posso usar um script/timer no host para buscar o ICS do Discourse autenticado e gravar:

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

Ao qual o Google Calendar/Outlook pode se inscrever como uma URL ICS pública normal.

Portanto, do meu ponto de vista, o lado do Discourse parece resolvido agora; a lacuna prática restante é principalmente que os principais clientes de calendário não lidam muito bem com feeds ICS autenticados, razão pela qual estou recorrendo a uma abordagem de proxy público/arquivo estático por enquanto.

Também estou assumindo que o Certbot é a rota mais simples aqui, já que ele pode gerenciar a emissão/renovação do Let’s Encrypt diretamente contra o Nginx do host. Eu também poderia usar acme.sh, mas minha impressão é que seria mais uma escolha manual do que o caminho mais direto para esta configuração específica.

Espera, o quê?

Eu estou usando com meu Google Agenda sem problemas, assim como alguns dos meus colegas.

Que parte disso é incompatível com o Google Agenda!?

Ah, obrigado, isso ajuda a restringir.

Do meu lado, o Google Agenda aceita a URL de assinatura (via “De URL”), mas o comportamento que estou vendo é:

  • o calendário é adicionado com sucesso
  • no entanto, ele não mostra nenhum evento

Portanto, não é um caso de a URL ser rejeitada - é mais que o feed parece estar vazio da perspectiva do Google.

Dado que o ICS bruto contém claramente entradas VEVENT (por exemplo, com UID, DTSTART, SUMMARY, etc.), isso me faz pensar que pode ser algo como:

  • O Google filtrando eventos passados (a maior parte dos meus dados de teste são históricos)
  • ou algo sobre como o feed está sendo interpretado (por exemplo, intervalo de tempo, caching, ou headers)

Avise-me se há algo específico que você gostaria que eu verificasse no próprio feed.

2 curtidas

Você pode verificar /logs em busca de erros? Acabei de corrigir um em que eventos recorrentes antigos estavam fazendo com que o feed falhasse.

Se foi o mesmo erro, você precisa atualizar.

Eu teria que procurar mais atrás, antes das 19h, pois há muitos avisos/erros relacionados ao Discourse AI - limite de token

1 curtida
1 curtida