mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-04-25 12:32:06 +00:00
Compare commits
15 Commits
v0.3.3
...
newer-medi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0188a01871 | ||
|
|
434b5118cc | ||
|
|
4185a33747 | ||
|
|
829307c83b | ||
|
|
2bd7a92256 | ||
|
|
bfa33f8713 | ||
|
|
040cf29051 | ||
|
|
80bc1cd78a | ||
|
|
78994deb1e | ||
|
|
714b3e7144 | ||
|
|
1cd57f40f6 | ||
|
|
da9a0eb77b | ||
|
|
37b2c90e62 | ||
|
|
ba150a1185 | ||
|
|
ddce9496f2 |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -75,8 +75,8 @@ jobs:
|
||||
- name: Apply Nix binary cache configuration
|
||||
run: |
|
||||
sudo tee -a /etc/nix/nix.conf > /dev/null <<EOF
|
||||
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit
|
||||
extra-trusted-public-keys = conduit:Isq8FGyEC6FOXH6nD+BOeAA+bKp6X6UIbupSlGEPuOg= conduwuit:lYPVh7o1hLu1idH4Xt2QHaRa49WRGSAqzcfFd94aOTw=
|
||||
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems
|
||||
extra-trusted-public-keys = conduit:Isq8FGyEC6FOXH6nD+BOeAA+bKp6X6UIbupSlGEPuOg= conduwuit:lYPVh7o1hLu1idH4Xt2QHaRa49WRGSAqzcfFd94aOTw= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=
|
||||
EOF
|
||||
|
||||
- name: Use alternative Nix binary caches if specified
|
||||
@@ -107,6 +107,14 @@ jobs:
|
||||
- name: Run Complement tests
|
||||
run: |
|
||||
direnv exec . bin/complement 'complement_src' 'complement_test_logs.jsonl' 'complement_test_results.jsonl'
|
||||
cp -v -f result complement_oci_image.tar.gz
|
||||
|
||||
- name: Upload Complement OCI image
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: complement_oci_image.tar.gz
|
||||
path: complement_oci_image.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Complement logs
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -132,7 +140,7 @@ jobs:
|
||||
run: |
|
||||
echo '# Complement diff results' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```diff' >> $GITHUB_STEP_SUMMARY
|
||||
tail -n 50 complement_test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
|
||||
tail -n 100 complement_test_output.log | sed 's/\x1b\[[0-9;]*m//g' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Update Job Summary
|
||||
|
||||
@@ -35,6 +35,10 @@ before_script:
|
||||
- if command -v nix > /dev/null && [ -n "$ATTIC_ENDPOINT" ]; then echo "extra-substituters = $ATTIC_ENDPOINT" >> /etc/nix/nix.conf; fi
|
||||
- if command -v nix > /dev/null && [ -n "$ATTIC_PUBLIC_KEY" ]; then echo "extra-trusted-public-keys = $ATTIC_PUBLIC_KEY" >> /etc/nix/nix.conf; fi
|
||||
|
||||
# Add Lix binary cache
|
||||
- if command -v nix > /dev/null; then echo "extra-substituters = https://cache.lix.systems" >> /etc/nix/nix.conf; fi
|
||||
- if command -v nix > /dev/null; then echo "extra-trusted-public-keys = cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=" >> /etc/nix/nix.conf; fi
|
||||
|
||||
# Add crane binary cache
|
||||
- if command -v nix > /dev/null; then echo "extra-substituters = https://crane.cachix.org" >> /etc/nix/nix.conf; fi
|
||||
- if command -v nix > /dev/null; then echo "extra-trusted-public-keys = crane.cachix.org-1:8Scfpmn9w+hGdXH/Q9tTLiYAE/2dnJYRJP7kl80GuRk=" >> /etc/nix/nix.conf; fi
|
||||
@@ -49,12 +53,15 @@ before_script:
|
||||
# Allow .envrc
|
||||
- if command -v nix > /dev/null; then direnv allow; fi
|
||||
|
||||
# Cache attic client
|
||||
- if command -v nix > /dev/null; then ./bin/nix-build-and-cache --inputs-from . attic; fi
|
||||
|
||||
# Set CARGO_HOME to a cacheable path
|
||||
- export CARGO_HOME="$(git rev-parse --show-toplevel)/.gitlab-ci.d/cargo"
|
||||
|
||||
ci:
|
||||
stage: ci
|
||||
image: nixos/nix:2.22.0
|
||||
image: nixos/nix:2.22.1
|
||||
script:
|
||||
# Cache CI dependencies
|
||||
- ./bin/nix-build-and-cache ci
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -2931,7 +2931,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rust-librocksdb-sys"
|
||||
version = "0.21.0+9.1.1"
|
||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=c5cd6bd25152ef1f8a488761351da0c3d29ed93a#c5cd6bd25152ef1f8a488761351da0c3d29ed93a"
|
||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#6f0afedb3c29239b1d8a15a97ed8e6b74e0a9b33"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bzip2-sys",
|
||||
@@ -2948,7 +2948,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rust-rocksdb"
|
||||
version = "0.25.0"
|
||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=c5cd6bd25152ef1f8a488761351da0c3d29ed93a#c5cd6bd25152ef1f8a488761351da0c3d29ed93a"
|
||||
source = "git+https://github.com/zaidoon1/rust-rocksdb?branch=master#6f0afedb3c29239b1d8a15a97ed8e6b74e0a9b33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rust-librocksdb-sys",
|
||||
|
||||
@@ -299,8 +299,7 @@ default-features = false
|
||||
|
||||
[dependencies.rust-rocksdb]
|
||||
git = "https://github.com/zaidoon1/rust-rocksdb"
|
||||
rev = "c5cd6bd25152ef1f8a488761351da0c3d29ed93a"
|
||||
#branch = "master"
|
||||
branch = "master"
|
||||
optional = true
|
||||
default-features = true
|
||||
features = ["multi-threaded-cf", "zstd"]
|
||||
|
||||
@@ -15,7 +15,7 @@ LOG_FILE="$2"
|
||||
# A `.jsonl` file to write test results to
|
||||
RESULTS_FILE="$3"
|
||||
|
||||
OCI_IMAGE="complement-conduit:dev"
|
||||
OCI_IMAGE="complement-conduit:main"
|
||||
|
||||
toplevel="$(git rev-parse --show-toplevel)"
|
||||
|
||||
@@ -31,7 +31,7 @@ set +o pipefail
|
||||
env \
|
||||
-C "$COMPLEMENT_SRC" \
|
||||
COMPLEMENT_BASE_IMAGE="$OCI_IMAGE" \
|
||||
go test -vet=off -timeout 1h -json ./tests | tee "$LOG_FILE"
|
||||
go test -tags="conduwuit_blacklist" -v -timeout 1h -json ./tests | tee "$LOG_FILE"
|
||||
set -o pipefail
|
||||
|
||||
# Post-process the results into an easy-to-compare format, sorted by Test name for reproducible results
|
||||
|
||||
2
debian/README.md
vendored
2
debian/README.md
vendored
@@ -22,7 +22,7 @@ # conduwuit for Debian
|
||||
Running
|
||||
-------
|
||||
|
||||
The package uses the `conduwuit.service` systemd unit file to start and
|
||||
The package uses the [`conduwuit.service`](../configuration.md#example-systemd-unit-file) systemd unit file to start and
|
||||
stop conduwuit. It loads the configuration file mentioned above to set up the
|
||||
environment before running the server.
|
||||
|
||||
|
||||
@@ -3,3 +3,9 @@ # Example configuration
|
||||
``` toml
|
||||
{{#include ../conduwuit-example.toml}}
|
||||
```
|
||||
|
||||
# Example systemd unit file
|
||||
|
||||
```
|
||||
{{#include ../debian/conduwuit.service}}
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ ## Forwarding ports in the firewall or the router
|
||||
|
||||
## Setting up a systemd service
|
||||
|
||||
The systemd unit for conduwuit can be found [here](../../debian/conduwuit.service). You may need to change the `ExecStart=` path to where you placed the conduwuit binary.
|
||||
The systemd unit for conduwuit can be found [here](../configuration.md#example-systemd-unit-file). You may need to change the `ExecStart=` path to where you placed the conduwuit binary.
|
||||
|
||||
## Creating the conduwuit configuration file
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# conduwuit for NixOS
|
||||
|
||||
conduwuit can be acquired by Nix from various places:
|
||||
conduwuit can be acquired by [Lix][lix] from various places:
|
||||
|
||||
* The `flake.nix` at the root of the repo
|
||||
* The `default.nix` at the root of the repo
|
||||
@@ -26,5 +26,6 @@ # conduwuit for NixOS
|
||||
or `default.nix` and set [`services.matrix-conduit.package`][package]
|
||||
appropriately.
|
||||
|
||||
[lix]: https://lix.systems/
|
||||
[module]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit
|
||||
[package]: https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit.package
|
||||
|
||||
@@ -5,13 +5,16 @@ ## Complement
|
||||
Have a look at [Complement's repository][complement] for an explanation of what
|
||||
it is.
|
||||
|
||||
To test against Complement, with Nix and direnv installed and set up, you can
|
||||
either:
|
||||
To test against Complement, with [Lix][lix] and direnv installed and set up, you can:
|
||||
|
||||
* Run `./bin/complement "$COMPLEMENT_SRC" ./path/to/logs.jsonl ./path/to/results.jsonl`
|
||||
to build a Complement image, run the tests, and output the logs and results
|
||||
to the specified paths
|
||||
to the specified paths. This will also output the OCI image at `result`
|
||||
* Run `nix build .#complement` from the root of the repository to just build a
|
||||
Complement image
|
||||
Complement OCI image outputted to `result` (it's a `.tar.gz` file)
|
||||
* Or download the latest Complement OCI image from the CI workflow artifacts output
|
||||
from the commit/revision you want to test (e.g. from main) [here][ci-workflows]
|
||||
|
||||
[lix]: https://lix.systems/
|
||||
[ci-workflows]: https://github.com/girlbossceo/conduwuit/actions/workflows/ci.yml?query=event%3Apush+is%3Asuccess+actor%3Agirlbossceo
|
||||
[complement]: https://github.com/matrix-org/complement
|
||||
|
||||
30
flake.lock
generated
30
flake.lock
generated
@@ -26,11 +26,11 @@
|
||||
"complement": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1714472853,
|
||||
"narHash": "sha256-CNRHSZe3TE+3tFj2dHNyxTMjDqL0MKY3P/3jqUgA7YE=",
|
||||
"lastModified": 1714661560,
|
||||
"narHash": "sha256-E1ZiUbOgo7rWo8zt2M2vzCVSykCxK0Ot2dUAxTL6cpU=",
|
||||
"owner": "matrix-org",
|
||||
"repo": "complement",
|
||||
"rev": "891d18872c153d39a9ce63b545045efddb845738",
|
||||
"rev": "370a014dca0f720614e0c8f68b9a3e66ecf7f516",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -68,11 +68,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1713738183,
|
||||
"narHash": "sha256-qd/MuLm7OfKQKyd4FAMqV4H6zYyOfef5lLzRrmXwKJM=",
|
||||
"lastModified": 1715274763,
|
||||
"narHash": "sha256-3Iv1PGHJn9sV3HO4FlOVaaztOxa9uGLfOmUWrH7v7+A=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "f6c6a2fb1b8bd9b65d65ca9342dd0eb180a63f11",
|
||||
"rev": "27025ab71bdca30e7ed0a16c88fd74c5970fc7f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -90,11 +90,11 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1714544767,
|
||||
"narHash": "sha256-kF1bX+YFMedf1g0PAJYwGUkzh22JmULtj8Rm4IXAQKs=",
|
||||
"lastModified": 1715322226,
|
||||
"narHash": "sha256-ezoe/FwfJpA7sskLoLP2iwfwkYnscEFCP6Vk5kPwh9k=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "73124e1356bde9411b163d636b39fe4804b7ca45",
|
||||
"rev": "297c756ba6249d483c1dafe42378560458842173",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -221,11 +221,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1713537308,
|
||||
"narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=",
|
||||
"lastModified": 1715266358,
|
||||
"narHash": "sha256-doPgfj+7FFe9rfzWo1siAV2mVCasW+Bh8I1cToAXEE4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f",
|
||||
"rev": "f1010e0469db743d14519a1efd37e23f8513d714",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -268,11 +268,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1713628977,
|
||||
"narHash": "sha256-iN5QUlUq527lswmBC+RopfXdu6Xx7mmTaBSH2l59FtM=",
|
||||
"lastModified": 1715255944,
|
||||
"narHash": "sha256-vLLgYpdtKBaGYTamNLg1rbRo1bPXp4Jgded/gnprPVw=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "55d9a533b309119c8acd13061581b43ae8840823",
|
||||
"rev": "5bf2f85c8054d80424899fa581db1b192230efb5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -16,6 +16,7 @@ stdenv.mkDerivation {
|
||||
"conduwuit-example.toml"
|
||||
"CONTRIBUTING.md"
|
||||
"README.md"
|
||||
"debian/conduwuit.service"
|
||||
"debian/README.md"
|
||||
"docs"
|
||||
];
|
||||
|
||||
@@ -53,7 +53,7 @@ in
|
||||
|
||||
dockerTools.buildImage {
|
||||
name = "complement-${main.pname}";
|
||||
tag = "dev";
|
||||
tag = "main";
|
||||
|
||||
copyToRoot = buildEnv {
|
||||
name = "root";
|
||||
@@ -81,7 +81,7 @@ dockerTools.buildImage {
|
||||
|
||||
Env = [
|
||||
"SSL_CERT_FILE=/complement/ca/ca.crt"
|
||||
"CONDUIT_CONFIG=${./config.toml}"
|
||||
"CONDUWUIT_CONFIG=${./config.toml}"
|
||||
];
|
||||
|
||||
ExposedPorts = {
|
||||
|
||||
@@ -66,7 +66,14 @@ commonAttrs = {
|
||||
# right thing here.
|
||||
pkgsBuildHost.rustPlatform.bindgenHook
|
||||
]
|
||||
++ lib.optionals stdenv.isDarwin [ libiconv ];
|
||||
++ lib.optionals stdenv.isDarwin [
|
||||
# https://github.com/NixOS/nixpkgs/issues/206242
|
||||
libiconv
|
||||
|
||||
# https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell
|
||||
# https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612
|
||||
pkgsBuildHost.darwin.apple_sdk.frameworks.Security
|
||||
];
|
||||
};
|
||||
in
|
||||
|
||||
@@ -85,8 +92,7 @@ craneLib.buildPackage ( commonAttrs // {
|
||||
|
||||
# This is redundant with CI
|
||||
cargoTestCommand = "";
|
||||
|
||||
# This is redundant with CI
|
||||
cargoCheckCommand = "";
|
||||
doCheck = false;
|
||||
|
||||
# https://crane.dev/faq/rebuilds-bindgen.html
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use ruma::api::client::{
|
||||
error::{ErrorKind, RetryAfter},
|
||||
media::{
|
||||
create_content, get_content, get_content_as_filename, get_content_thumbnail, get_media_config,
|
||||
create_content, create_mxc_uri, get_content, get_content_as_filename, get_content_thumbnail, get_media_config,
|
||||
get_media_preview,
|
||||
},
|
||||
};
|
||||
@@ -19,7 +19,9 @@
|
||||
services,
|
||||
utils::{
|
||||
self,
|
||||
content_disposition::{content_disposition_type, make_content_disposition, sanitise_filename},
|
||||
content_disposition::{
|
||||
content_disposition_type, make_content_disposition, make_content_type, sanitise_filename,
|
||||
},
|
||||
server_name::server_is_ours,
|
||||
},
|
||||
Error, Result, Ruma, RumaResponse,
|
||||
@@ -57,6 +59,29 @@ pub(crate) async fn get_media_config_v1_route(
|
||||
get_media_config_route(body).await.map(RumaResponse)
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/media/v1/create`
|
||||
///
|
||||
/// Creates a MXC URI.
|
||||
///
|
||||
/// <https://spec.matrix.org/latest/client-server-api/#post_matrixmediav1create>
|
||||
///
|
||||
/// TODO: implement `unused_expires_at`, prevent MXC URI creation spam by
|
||||
/// keeping track of created MXC URIs with no content pushed to them per-user
|
||||
pub(crate) async fn create_mxc_uri(body: Ruma<create_mxc_uri::v1::Request>) -> Result<create_mxc_uri::v1::Response> {
|
||||
let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let mxc = format!(
|
||||
"mxc://{}/{}",
|
||||
services().globals.server_name(),
|
||||
utils::random_string(MXC_LENGTH)
|
||||
);
|
||||
|
||||
Ok(create_mxc_uri::v1::Response {
|
||||
content_uri: mxc.into(),
|
||||
unused_expires_at: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/media/v3/preview_url`
|
||||
///
|
||||
/// Returns URL preview.
|
||||
@@ -127,6 +152,8 @@ pub(crate) async fn create_content_route(
|
||||
utils::random_string(MXC_LENGTH)
|
||||
);
|
||||
|
||||
let content_type = Some(make_content_type(&body.file, &body.content_type).to_owned());
|
||||
|
||||
services()
|
||||
.media
|
||||
.create(
|
||||
@@ -137,20 +164,18 @@ pub(crate) async fn create_content_route(
|
||||
.map(|filename| {
|
||||
format!(
|
||||
"{}; filename={}",
|
||||
content_disposition_type(&body.file, &body.content_type),
|
||||
content_disposition_type(&body.file, &content_type),
|
||||
sanitise_filename(filename.to_owned())
|
||||
)
|
||||
})
|
||||
.as_deref(),
|
||||
body.content_type.as_deref(),
|
||||
content_type.as_deref(),
|
||||
&body.file,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let content_uri = mxc.into();
|
||||
|
||||
Ok(create_content::v3::Response {
|
||||
content_uri,
|
||||
content_uri: mxc.into(),
|
||||
blurhash: None,
|
||||
})
|
||||
}
|
||||
@@ -189,6 +214,7 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
|
||||
}) = services().media.get(mxc.clone()).await?
|
||||
{
|
||||
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||
let content_type = Some(make_content_type(&file, &content_type).to_owned());
|
||||
|
||||
Ok(get_content::v3::Response {
|
||||
file,
|
||||
@@ -216,10 +242,11 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
|
||||
&response.content_type,
|
||||
response.content_disposition,
|
||||
));
|
||||
let content_type = Some(make_content_type(&response.file, &response.content_type).to_owned());
|
||||
|
||||
Ok(get_content::v3::Response {
|
||||
file: response.file,
|
||||
content_type: response.content_type,
|
||||
content_type,
|
||||
content_disposition,
|
||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||
@@ -267,6 +294,7 @@ pub(crate) async fn get_content_as_filename_route(
|
||||
}) = services().media.get(mxc.clone()).await?
|
||||
{
|
||||
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||
let content_type = Some(make_content_type(&file, &content_type).to_owned());
|
||||
|
||||
Ok(get_content_as_filename::v3::Response {
|
||||
file,
|
||||
@@ -291,10 +319,13 @@ pub(crate) async fn get_content_as_filename_route(
|
||||
&remote_content_response.content_type,
|
||||
remote_content_response.content_disposition,
|
||||
));
|
||||
let content_type = Some(
|
||||
make_content_type(&remote_content_response.file, &remote_content_response.content_type).to_owned(),
|
||||
);
|
||||
|
||||
Ok(get_content_as_filename::v3::Response {
|
||||
content_disposition,
|
||||
content_type: remote_content_response.content_type,
|
||||
content_type,
|
||||
file: remote_content_response.file,
|
||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.into()),
|
||||
@@ -359,6 +390,7 @@ pub(crate) async fn get_content_thumbnail_route(
|
||||
.await?
|
||||
{
|
||||
let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
|
||||
let content_type = Some(make_content_type(&file, &content_type).to_owned());
|
||||
|
||||
Ok(get_content_thumbnail::v3::Response {
|
||||
file,
|
||||
@@ -371,7 +403,7 @@ pub(crate) async fn get_content_thumbnail_route(
|
||||
if services()
|
||||
.globals
|
||||
.prevent_media_downloads_from()
|
||||
.contains(&body.server_name.clone())
|
||||
.contains(&body.server_name)
|
||||
{
|
||||
// we'll lie to the client and say the blocked server's media was not found and
|
||||
// log. the client has no way of telling anyways so this is a security bonus.
|
||||
@@ -415,10 +447,13 @@ pub(crate) async fn get_content_thumbnail_route(
|
||||
&get_thumbnail_response.content_type,
|
||||
get_thumbnail_response.content_disposition,
|
||||
));
|
||||
let content_type = Some(
|
||||
make_content_type(&get_thumbnail_response.file, &get_thumbnail_response.content_type).to_owned(),
|
||||
);
|
||||
|
||||
Ok(get_content_thumbnail::v3::Response {
|
||||
file: get_thumbnail_response.file,
|
||||
content_type: get_thumbnail_response.content_type,
|
||||
content_type,
|
||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||
content_disposition,
|
||||
@@ -486,20 +521,22 @@ async fn get_remote_content(
|
||||
content_response.content_disposition,
|
||||
));
|
||||
|
||||
let content_type = Some(make_content_type(&content_response.file, &content_response.content_type).to_owned());
|
||||
|
||||
services()
|
||||
.media
|
||||
.create(
|
||||
None,
|
||||
mxc.to_owned(),
|
||||
content_disposition.as_deref(),
|
||||
content_response.content_type.as_deref(),
|
||||
content_type.as_deref(),
|
||||
&content_response.file,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(get_content::v3::Response {
|
||||
file: content_response.file,
|
||||
content_type: content_response.content_type,
|
||||
content_type,
|
||||
content_disposition,
|
||||
cross_origin_resource_policy: Some(CORP_CROSS_ORIGIN.to_owned()),
|
||||
cache_control: Some(CACHE_CONTROL_IMMUTABLE.to_owned()),
|
||||
|
||||
@@ -133,6 +133,7 @@ pub(crate) fn routes(config: &Config) -> Router {
|
||||
.ruma_route(client_server::get_media_config_route)
|
||||
.ruma_route(client_server::get_media_preview_route)
|
||||
.ruma_route(client_server::create_content_route)
|
||||
.ruma_route(client_server::create_mxc_uri)
|
||||
// legacy v1 media routes
|
||||
.route(
|
||||
"/_matrix/media/v1/preview_url",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
use infer::MatcherType;
|
||||
|
||||
use crate::debug_info;
|
||||
|
||||
const ATTACHMENT: &str = "attachment";
|
||||
const INLINE: &str = "inline";
|
||||
const APPLICATION_OCTET_STREAM: &str = "application/octet-stream";
|
||||
const IMAGE_SVG_XML: &str = "image/svg+xml";
|
||||
|
||||
/// Returns a Content-Disposition of `attachment` or `inline`, depending on the
|
||||
/// *parsed* contents of the file uploaded via format magic keys using `infer`
|
||||
/// crate (basically libmagic without needing libmagic).
|
||||
@@ -10,17 +17,48 @@
|
||||
///
|
||||
/// TODO: add a "strict" function for comparing the Content-Type with what we
|
||||
/// detected: `file_type.mime_type() != content_type`
|
||||
pub(crate) fn content_disposition_type(buf: &[u8], _content_type: &Option<String>) -> &'static str {
|
||||
#[tracing::instrument(skip(buf))]
|
||||
pub(crate) fn content_disposition_type(buf: &[u8], content_type: &Option<String>) -> &'static str {
|
||||
let Some(file_type) = infer::get(buf) else {
|
||||
return "attachment";
|
||||
return ATTACHMENT;
|
||||
};
|
||||
|
||||
debug_info!("MIME type: {}", file_type.mime_type());
|
||||
|
||||
match file_type.matcher_type() {
|
||||
MatcherType::Image | MatcherType::Audio | MatcherType::Text | MatcherType::Video => "inline",
|
||||
_ => "attachment",
|
||||
MatcherType::Image | MatcherType::Audio | MatcherType::Text | MatcherType::Video => {
|
||||
if file_type.mime_type().contains("xml") {
|
||||
ATTACHMENT
|
||||
} else {
|
||||
INLINE
|
||||
}
|
||||
},
|
||||
_ => ATTACHMENT,
|
||||
}
|
||||
}
|
||||
|
||||
/// overrides the Content-Type with what we detected
|
||||
///
|
||||
/// SVG is special-cased due to the MIME type being classified as `text/xml` but
|
||||
/// browsers need `image/svg+xml`
|
||||
#[tracing::instrument(skip(buf))]
|
||||
pub(crate) fn make_content_type(buf: &[u8], content_type: &Option<String>) -> &'static str {
|
||||
let Some(file_type) = infer::get(buf) else {
|
||||
debug_info!("Failed to infer the file's contents");
|
||||
return APPLICATION_OCTET_STREAM;
|
||||
};
|
||||
|
||||
let Some(claimed_content_type) = content_type else {
|
||||
return file_type.mime_type();
|
||||
};
|
||||
|
||||
if claimed_content_type.contains("svg") && file_type.mime_type().contains("xml") {
|
||||
return IMAGE_SVG_XML;
|
||||
}
|
||||
|
||||
file_type.mime_type()
|
||||
}
|
||||
|
||||
/// sanitises the file name for the Content-Disposition using
|
||||
/// `sanitize_filename` crate
|
||||
#[tracing::instrument]
|
||||
@@ -36,8 +74,10 @@ pub(crate) fn sanitise_filename(filename: String) -> String {
|
||||
/// creates the final Content-Disposition based on whether the filename exists
|
||||
/// or not.
|
||||
///
|
||||
/// if filename exists: `Content-Disposition: attachment/inline;
|
||||
/// filename=filename.ext` else: `Content-Disposition: attachment/inline`
|
||||
/// if filename exists:
|
||||
/// `Content-Disposition: attachment/inline; filename=filename.ext`
|
||||
///
|
||||
/// else: `Content-Disposition: attachment/inline`
|
||||
#[tracing::instrument(skip(file))]
|
||||
pub(crate) fn make_content_disposition(
|
||||
file: &[u8], content_type: &Option<String>, content_disposition: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user