Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,357 changes: 826 additions & 531 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2021"
rust-version = "1.88.0"

[dependencies]
redis = { version = "0.31.0", default-features = false, features = ["tokio-comp", "aio", "cluster", "cluster-async", "keep-alive", "tls-rustls", "tokio-rustls-comp", "tls-rustls-webpki-roots", "tls-rustls-insecure"] }
redis = { version = "1.0.5", default-features = false, features = ["tokio-comp", "aio", "cluster", "cluster-async", "tls-rustls", "tokio-rustls-comp", "tls-rustls-webpki-roots", "tls-rustls-insecure"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.142"
thiserror = "2.0.12"
Expand All @@ -22,21 +22,22 @@ dashmap = "6.1.0"
once_cell = "1.21.3"
miette = { version = "7.6.0", features = ["fancy"] }
smallvec = { version = "1.15.1", features = ["serde"] }
reqwest = { version = "0.12.22", default-features = false, features = ["rustls-tls", "rustls-tls-native-roots", "json"] }
reqwest = { version = "0.13.2", features = ["json"] }
warp-real-ip = "0.2.0"
parse-display = "0.10.0"
rand = { version = "0.8.5", features = ["small_rng"] }
ahash = "0.8.12"
flexi_logger = { version = "0.29.8", features = ["colors"] }
flexi_logger = { version = "0.31.8", features = ["colors"] }
tokio-stream = { version = "0.1.17", features = ["net"] }
nextcloud-config-parser = "0.15.1"
url = "2.5.4"
clap = { version = "4.5.43", features = ["derive"] }
sd-notify = { version = "0.4.5", optional = true }
sd-notify = { version = "0.5.0", optional = true }
webpki-root-certs = "1.0.6"

[dev-dependencies]
mini-redis = "0.4.1"
tokio-tungstenite = "0.26.2"
tokio-tungstenite = "0.28.0"
http-auth-basic = "0.3.5"
test_client = { path = "test_client" }

Expand Down
4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
};

devShells = {
default = cross-naersk'.mkShell targets {
default = cross-naersk'.mkShell ["x86_64-unknown-linux-gnu"] {
nativeBuildInputs = with pkgs; [
(rust-bin.stable.latest.default.override {targets = targets ++ [hostTarget];})
krankerl
Expand All @@ -126,7 +126,7 @@
phpPackages.composer
];
};
msrv = cross-naersk'.mkShell targets {
msrv = cross-naersk'.mkShell ["x86_64-unknown-linux-gnu"] {
nativeBuildInputs = with pkgs; [
msrvToolchain
];
Expand Down
28 changes: 15 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ impl PartialConfig {
let max_connection_time = parse_var("MAX_CONNECTION_TIME")?;

let redis = redis.map(|redis| {
let addr = map_redis_addr(redis.addr);
let addr = map_redis_addr(redis.addr().clone());

let accept_invalid_hostname = redis_tls_dont_validate_hostname
.filter(|b| *b != 0)
Expand All @@ -315,9 +315,9 @@ impl PartialConfig {

RedisConfig::Single(RedisConnectionInfo {
addr,
db: redis.redis.db,
username: redis.redis.username,
password: redis.redis.password,
db: redis.redis_settings().db(),
username: redis.redis_settings().username().map(String::from),
password: redis.redis_settings().password().map(String::from),
tls_params,
})
});
Expand Down Expand Up @@ -357,7 +357,7 @@ impl PartialConfig {
0 => None,
1 => {
let redis = opt.redis_url.into_iter().next().unwrap();
let addr = map_redis_addr(redis.addr);
let addr = map_redis_addr(redis.addr().clone());

let redis_tls = matches!(addr, RedisConnectionAddr::Tcp { tls: true, .. });

Expand All @@ -371,17 +371,17 @@ impl PartialConfig {

Some(RedisConfig::Single(RedisConnectionInfo {
addr,
db: redis.redis.db,
username: redis.redis.username,
password: redis.redis.password,
db: redis.redis_settings().db(),
username: redis.redis_settings().username().map(String::from),
password: redis.redis_settings().password().map(String::from),
tls_params,
}))
}
_ => {
let addr: Vec<_> = opt
.redis_url
.iter()
.map(|redis| map_redis_addr(redis.addr.clone()))
.map(|redis| map_redis_addr(redis.addr().clone()))
.collect();

let redis_tls = matches!(
Expand All @@ -397,12 +397,13 @@ impl PartialConfig {
insecure: opt.redis_tls_insecure,
});

let redis = opt.redis_url.into_iter().next().unwrap().redis;
let redis = opt.redis_url.into_iter().next().unwrap();
let redis = redis.redis_settings();
Some(RedisConfig::Cluster(RedisClusterConnectionInfo {
addr,
db: redis.db,
username: redis.username,
password: redis.password,
db: redis.db(),
username: redis.username().map(String::from),
password: redis.password().map(String::from),
tls_params,
}))
}
Expand Down Expand Up @@ -483,5 +484,6 @@ fn map_redis_addr(addr: ConnectionAddr) -> RedisConnectionAddr {
tls: true,
},
ConnectionAddr::Unix(path) => RedisConnectionAddr::Unix { path },
_ => unreachable!("unknown redis address"),
}
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async fn run(config: Config, log_handle: LoggerHandle) -> Result<()> {

// tell SystemD that sockets have been bound to their addresses
#[cfg(feature = "systemd")]
sd_notify::notify(true, &[sd_notify::NotifyState::Ready]).map_err(Error::SystemD)?;
sd_notify::notify(&[sd_notify::NotifyState::Ready]).map_err(Error::SystemD)?;

spawn(listen_loop(app, listen_cancel_handle));

Expand Down
9 changes: 7 additions & 2 deletions src/nc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::error::{AuthenticationError, NextCloudError};
use crate::{Result, UserId};
use reqwest::header::HeaderName;
use reqwest::{Response, StatusCode, Url};
use reqwest::{Certificate, Response, StatusCode, Url};
use std::fmt::Write;
use std::net::IpAddr;

Expand All @@ -21,7 +21,12 @@ impl Client {
pub fn new(base_url: &str, allow_self_signed: bool) -> Result<Self, NextCloudError> {
let base_url = Url::parse(base_url)?;
let http = reqwest::Client::builder()
.danger_accept_invalid_certs(allow_self_signed)
.tls_certs_merge(
webpki_root_certs::TLS_SERVER_ROOT_CERTS
.iter()
.map(|root| Certificate::from_der(root).unwrap()),
)
.tls_danger_accept_invalid_certs(allow_self_signed)
.build()?;
Ok(Client { http, base_url })
}
Expand Down
65 changes: 31 additions & 34 deletions src/redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use redis::aio::{MultiplexedConnection, PubSub};
use redis::cluster::ClusterClient;
use redis::cluster_async::ClusterConnection;
use redis::{
AsyncCommands, Client, ClientTlsConfig, ConnectionAddr, ConnectionInfo, RedisConnectionInfo,
RedisError, TlsCertificates,
AsyncCommands, Client, ClientTlsConfig, ConnectionAddr, ConnectionInfo, IntoConnectionInfo,
RedisConnectionInfo, RedisError, TlsCertificates,
};
use std::fs::read;

Expand Down Expand Up @@ -56,25 +56,27 @@ impl Redis {
pub fn open_single(
info: &nextcloud_config_parser::RedisConnectionInfo,
) -> Result<Client, RedisError> {
let redis = RedisConnectionInfo {
db: info.db,
username: info.username.clone(),
password: info.password.clone(),
protocol: Default::default(),
};
let mut redis = RedisConnectionInfo::default().set_db(info.db);
if let Some(username) = info.username.as_deref() {
redis = redis.set_username(username);
}
if let Some(password) = info.password.as_deref() {
redis = redis.set_password(password);
}
let connection_info = build_connection_info(info.addr.clone(), redis, info.tls_params.as_ref());
Ok(match info.tls_params.as_ref() {
None => Client::open(connection_info)?,
Some(tls_params) => {
// the redis library doesn't let us set both `danger_accept_invalid_hostnames` and certificates without this mess:
// `Client::build_with_tls` doesn't use the `danger_accept_invalid_hostnames` from the passed in info
// so we first use it to get build the certificates then take the connection info from it so we can configure it further
let mut connection_info =
let connection_info =
Client::build_with_tls(connection_info, build_tls_certificates(tls_params)?)?
.get_connection_info()
.clone();
connection_info
.addr
.addr()
.clone()
.set_danger_accept_invalid_hostnames(tls_params.accept_invalid_hostname);
Client::open(connection_info)?
}
Expand All @@ -86,48 +88,43 @@ fn build_connection_info(
redis: RedisConnectionInfo,
tls: Option<&RedisTlsParams>,
) -> ConnectionInfo {
match (addr, tls) {
let addr = match (addr, tls) {
(
RedisConnectionAddr::Tcp {
host,
port,
tls: false,
},
_,
) => ConnectionInfo {
addr: ConnectionAddr::Tcp(host, port),
redis,
},
) => ConnectionAddr::Tcp(host, port),
(
RedisConnectionAddr::Tcp {
host,
port,
tls: true,
},
tls_params,
) => ConnectionInfo {
addr: ConnectionAddr::TcpTls {
host,
port,
insecure: tls_params.map(|tls| tls.insecure).unwrap_or_default(),
tls_params: None,
},
redis,
) => ConnectionAddr::TcpTls {
host,
port,
insecure: tls_params.map(|tls| tls.insecure).unwrap_or_default(),
tls_params: None,
},
(RedisConnectionAddr::Unix { path }, _) => ConnectionInfo {
addr: ConnectionAddr::Unix(path),
redis,
},
}
(RedisConnectionAddr::Unix { path }, _) => ConnectionAddr::Unix(path),
};
addr.into_connection_info()
.unwrap()
.set_redis_settings(redis)
}

fn open_cluster(info: &RedisClusterConnectionInfo) -> Result<ClusterClient, RedisError> {
let redis = RedisConnectionInfo {
db: info.db,
username: info.username.clone(),
password: info.password.clone(),
protocol: Default::default(),
};
let mut redis = RedisConnectionInfo::default().set_db(info.db);
if let Some(username) = info.username.as_deref() {
redis = redis.set_username(username);
}
if let Some(password) = info.password.as_deref() {
redis = redis.set_password(password);
}
let mut builder =
ClusterClient::builder(info.addr.iter().map(|addr| {
build_connection_info(addr.clone(), redis.clone(), info.tls_params.as_ref())
Expand Down
6 changes: 3 additions & 3 deletions test_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ authors = ["Robin Appelman <robin@icewind.nl>"]
edition = "2018"

[dependencies]
tungstenite = { version = "0.26.2", features = ["rustls-tls-webpki-roots", "url"] }
tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots", "url"] }
serde_json = "1.0.142"
ureq = "2.12.1"
flexi_logger = { version = "0.29.8", features = ["colors"] }
ureq = "3.2.0"
flexi_logger = { version = "0.31.8", features = ["colors"] }
log = "0.4.27"
base64 = "0.22.1"
miette = { version = "7.6.0", features = ["fancy"] }
Expand Down
9 changes: 5 additions & 4 deletions test_client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,19 @@ fn main() -> Result<()> {

fn get_endpoint(nc_url: &str, user: &str, password: &str) -> Result<String> {
let raw = ureq::get(&format!("{nc_url}/ocs/v2.php/cloud/capabilities"))
.set(
.header(
"Authorization",
&format!(
"Basic {}",
base64::engine::general_purpose::STANDARD.encode(format!("{user}:{password}"))
),
)
.set("Accept", "application/json")
.set("OCS-APIREQUEST", "true")
.header("Accept", "application/json")
.header("OCS-APIREQUEST", "true")
.call()
.into_diagnostic()?
.into_string()
.into_body()
.read_to_string()
.into_diagnostic()?;
trace!("Capabilities response: {raw}");
let json: Value = serde_json::from_str(&raw)
Expand Down
Loading