Build Debian package / Build package (release) Canceled after 0s
build_desktop_and_deploy.yaml / Prepare (release) Canceled after 0s
Build and Deploy / prepare (release) Canceled after 0s
Deploy release / Deploy to Cloudflare Pages (release) Canceled after 0s
Build and Deploy / Trigger Pro pipeline (release) Canceled after 0s
Build and Deploy / Windows arm64 (release) Canceled after 0s
Build and Deploy / Windows x64 (release) Canceled after 0s
Build and Deploy / macOS (release) Canceled after 0s
Build and Deploy / Linux amd64 (sqlcipher static) (release) Canceled after 0s
Build and Deploy / Linux arm64 (sqlcipher static) (release) Canceled after 0s
Build and Deploy / ${{ needs.prepare.outputs.deploy == 'true' && 'Deploy' || 'Deploy (dry-run)' }} (release) Canceled after 0s
Build and Deploy / Deploy builds to ESS (release) Canceled after 0s
Synapse's own check_media_file_for_spam module can never see E2EE attachment content - only the client ever holds the decryption key. Adds two hooks that call a self-hosted scan service (https://axion1337.chat/_scan, deployed separately in the gitops repo): - DecryptFile.ts: scans every decrypted attachment (image/audio/video/ file all funnel through this one function via MediaEventHelper) before returning it as a Blob. - ContentMessages.ts: scans plaintext before encryption/upload in uploadFile(), the shared function behind all attachment uploads (main file, thumbnails, voice messages), regardless of room encryption state. New ContentScanRejectedError surfaces through the existing error- rendering paths (MediaProcessingError, upload failure dialog) using the same pattern as DecryptError/DownloadError/UploadFailedError. Live-tested: EICAR blocked pre-upload in encrypted rooms and DMs; receive-side hook also blocks EICAR sent by an unpatched client (app.element.io), confirming it isn't just self-protection for our own uploads. Fails open on scanner errors so an outage can't block all uploads/downloads.