URL do S3 CDN não está sendo usada em uploads que não são de imagem

Maybe related to S3 CDN URL ignored when uploading into posts.

At first I thought I had missed some configuration, but it’s reproducible here on meta:
https://meta.discourse.org/uploads/short-url/dw1U4hctATusBlHsUmWQXeme66j.csv (uploaded here) is a 302 redirect to
//assets-meta-cdck-prod-meta.s3.dualstack.us-west-1.amazonaws.com/original/3X/5/e/5ebb2cfb8cc907e8e8f7c6559a72d2f4a8ba2f8f.csv

Shouldn’t it redirect to https://d11a6trkgmumsb.cloudfront.net/original/3X/5/e/5ebb2cfb8cc907e8e8f7c6559a72d2f4a8ba2f8f.csv instead?

5 curtidas

Hmmm there may possibly be an issue here @martin can you investigate? We should probably redirect to the CDN if possible.

5 curtidas

This is a little bit tricky, I had a look at this just now. Basically we are always downloading from S3 with a presigned URL if we are doing a “force download”, which is what happens when we are clicking on the attachment link or clicking on the Download button on an image. This is so the appropriate content-disposition headers can be added:

attachment; filename="#{upload.original_filename}"; filename*=UTF-8''#{upload.original_filename}

I do not think it is possible to make the CDN URL behave in this way? The CDN URL for images is only used when displaying them inline, not when downloading them. Also in the case of secure images and attachments which have a private ACL the presigned URL must always be used.

2 curtidas

@martin em relação a links de anexos, não consigo ver como eles podem ser definidos para sempre “forçar download”. No momento, ao carregar um arquivo que não seja de imagem, a URL renderizada resultante é uma URL curta sem o parâmetro ?dl=1, que é resolvida para o valor do atributo url do upload correspondente (que não é uma URL pré-assinada e também falha em nosso caso, pois a URL não é a cdn_url do S3, mas uma construída que pode funcionar apenas para certos provedores S3).

Existe alguma maneira de forçar sempre o download de anexos, ou o comportamento atual é realmente um bug?

1 curtida

Você pode explicar melhor? Você está usando o Amazon S3 ou um provedor diferente? Se sim, qual?

1 curtida

Sim, parece que estou usando um provedor S3 não suportado (OVH Object Storage)

Com uma URL de endpoint de https://s3.de.ovh.cloud.net e uma s3 cdn_url configurada para https://storage.de.ovh.cloud.net/v1/<algum-id-de-usuário-único>/<o-nome-do-bucket>

Quando URLs curtas são resolvidas, o Discourse usa a URL do endpoint para construir a URL resultante (o que falha, pois não inclui o ID de usuário OVH correto - a parte na s3 cdn_url).

Forçar URLs curtas a terem dl=1 construiria uma presigned_url funcional, o que seria bom para mim.

Eu defini essas variáveis de ambiente (específicas de S3) dentro do YAML do contêiner:

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: DE
DISCOURSE_S3_ENDPOINT: https://s3.de.cloud.ovh.net
DISCOURSE_S3_ACCESS_KEY_ID: ...
DISCOURSE_S3_SECRET_ACCESS_KEY: ...
DISCOURSE_S3_CDN_URL: https://storage.de.ovh.cloud.net/v1/<algum-id-de-usuário-único>/<o-nome-do-bucket>
DISCOURSE_S3_UPLOAD_BUCKET: <o-nome-do-bucket>
DISCOURSE_S3_INSTALL_CORS_RULE: false
1 curtida

Talvez isso esteja fora do escopo deste tópico, mas se o comportamento atual for intencional, como ou onde se poderia substituir a renderização de URLs curtas no frontend? Estou pensando em simplesmente me conectar ao processo de cozimento de posts e, em seguida, anexar o parâmetro de consulta aos URLs curtos de anexos. Estou ciente de como escrever plugins js para o Discourse, mas na maioria das vezes tenho dificuldade em encontrar o Widget certo para “reabrir” ou a função para substituir.

Ok, então encontrei o local onde o Markdown para anexos é gerado e, pelo que entendi da API do plugin, não se pode (facilmente) substituí-lo (até acho que não se deveria fazer isso).

Então, meu pensamento inicial de adicionar um parâmetro ?dl=1 a esses URLs parece ser a maneira errada de fazer isso.

Em relação a não forçar downloads para short-urls resolvidos: Se entendi corretamente o argumento contra ACLs públicas em buckets S3, deve-se:

  1. Servir arquivos do S3 via CDN (inviável para anexos, como @martin apontou, pois podemos não conseguir definir corretamente o nome do arquivo para download neste caso)
  2. Criar uma URL pré-assinada para o objeto S3

Mas o comportamento atual não faz nem um nem outro e espera que o bucket S3 tenha uma ACL pública. Este também parece ser o caso para provedores S3 suportados (incluindo a Amazon), então eu perguntaria por que não tornar a opção force_download em Discourse.store.url_for o padrão como true ao resolver short-urls para stores S3?

1 curtida

Estou tendo o mesmo problema aqui, o que eu espero é que o arquivo atrás de uploads/short-url seja baixado ou redirecionado para a URL do CDN da S3.

2 curtidas

Estamos enfrentando o mesmo problema com o Cloudflare R2, pois ele não parece permitir o uso da URL S3 direta sem uma URL pré-assinada.
E o R2 não suporta ACL para buckets.

Parece que o Discourse adicionou recentemente uma opção “s3 use cdn url for all uploads” que resolve este problema.