├── .gitignore ├── .dockerignore ├── .env.example ├── Cargo.toml ├── compose.build.yaml ├── docker └── Dockerfile ├── compose.yaml ├── LICENSE ├── .devcontainer ├── devcontainer.json └── compose.yml ├── src ├── docker │ └── types.rs ├── utils.rs ├── main.rs ├── config.rs ├── docker.rs └── proxy.rs ├── .vscode └── launch.json ├── usecases.md ├── README.md ├── .github └── workflows │ └── publishImage.yml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .env -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | .env 3 | .git 4 | docker/ 5 | .devcontainer/ 6 | .vscode/ -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | PROXY_URL=http://dockerproxy:2375 2 | CONTAINER_NAMES=containerFoo,containerBar 3 | SCRUB_ENVS=true 4 | RUST_LOG=info,docker_proxy_filter=debug -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "docker-proxy-filter" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | dotenvy = "0.15.7" 8 | envy = "0.4.2" 9 | futures-util = "0.3.31" 10 | http = "1.3.1" 11 | ntex = { version = "2.16.0", features = ["tokio"] } 12 | regex = "1.11.3" 13 | serde = {version ="1.0.228", features = ["derive"] } 14 | serde_json = "1.0.145" 15 | tracing = "0.1.41" 16 | tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } 17 | url = "2.5.7" 18 | 19 | [profile.release] 20 | strip = true # Automatically strip symbols from the binary. 21 | opt-level = "z" # Optimize for size. 22 | lto = true 23 | codegen-units = 1 24 | -------------------------------------------------------------------------------- /compose.build.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | proxy-container: 3 | image: docker-proxy-filter 4 | build: 5 | dockerfile: docker/Dockerfile 6 | context: . 7 | env_file: .env 8 | ports: 9 | - 2375:2375 10 | socket-proxy: 11 | image: wollomatic/socket-proxy:1.10.0 12 | restart: unless-stopped 13 | user: 0:0 14 | mem_limit: 64M 15 | read_only: true 16 | cap_drop: 17 | - ALL 18 | security_opt: 19 | - no-new-privileges 20 | command: 21 | - '-loglevel=debug' 22 | - '-listenip=0.0.0.0' 23 | - '-allowfrom=proxy-container' 24 | 25 | - '-allowGET=/_ping|/(v1\..{1,2}/)?(info|version|containers|events).*' 26 | - '-allowbindmountfrom=/var/log,/tmp' # restrict bind mounts to specific directories 27 | - '-watchdoginterval=3600' # check once per hour for socket availability 28 | - '-stoponwatchdog' # halt program on error and let compose restart it 29 | - '-shutdowngracetime=5' # wait 5 seconds before shutting down 30 | volumes: 31 | - /var/run/docker.sock:/var/run/docker.sock:ro -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.90-bookworm as Builder 2 | 3 | WORKDIR /app 4 | 5 | RUN cargo init 6 | 7 | COPY Cargo.lock Cargo.toml ./ 8 | 9 | # build dummy project with dependencies to get them compiled and cached 10 | RUN cargo build --release --target $(rustc --print host-tuple) 11 | 12 | # copy full app code 13 | COPY src/ src/ 14 | # updated modified timestamp so build runs again 15 | RUN touch src/main.rs 16 | 17 | # build full app to host arch and copy to generic location 18 | RUN export ARCH=$(rustc --print host-tuple); \ 19 | cargo build --release --target $ARCH \ 20 | && mkdir build \ 21 | && cp target/$ARCH/release/docker-proxy-filter build/docker-proxy-filter 22 | 23 | FROM debian:bookworm-slim 24 | 25 | ENV RUST_LOG=info,docker_proxy_filter=debug 26 | 27 | # need ssl for web server 28 | RUN apt-get update && apt-get upgrade -y && apt-get install openssl -y && apt clean && rm -rf /var/lib/apt/lists/* 29 | # copy built app from generic location 30 | COPY --from=builder /app/build/docker-proxy-filter /usr/local/bin/docker-proxy-filter 31 | CMD ["docker-proxy-filter"] -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | proxy-container: 3 | image: foxxmd/docker-proxy-filter 4 | environment: 5 | - PROXY_URL=http://socket-proxy:2375 6 | - CONTAINER_NAME=foo,bar 7 | ports: 8 | - 2375:2375 9 | socket-proxy: 10 | image: wollomatic/socket-proxy:1.10.0 11 | restart: unless-stopped 12 | user: 0:0 13 | mem_limit: 64M 14 | read_only: true 15 | cap_drop: 16 | - ALL 17 | security_opt: 18 | - no-new-privileges 19 | command: 20 | - '-loglevel=debug' 21 | - '-listenip=0.0.0.0' 22 | - '-allowfrom=proxy-container' 23 | - '-allowHEAD=/_ping' 24 | - '-allowGET=/_ping|/(v1\..{1,2}/)?(info|version|containers|events).*' 25 | - '-allowbindmountfrom=/var/log,/tmp' # restrict bind mounts to specific directories 26 | - '-watchdoginterval=3600' # check once per hour for socket availability 27 | - '-stoponwatchdog' # halt program on error and let compose restart it 28 | - '-shutdowngracetime=5' # wait 5 seconds before shutting down 29 | volumes: 30 | - /var/run/docker.sock:/var/run/docker.sock:ro -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 FoxxMD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dockerlog", 3 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 4 | "workspaceFolder": "/workspaces", 5 | "service": "dev", 6 | "dockerComposeFile": ["compose.yml"], 7 | // Features to add to the dev container. More info: https://containers.dev/features. 8 | 9 | 10 | // Use 'mounts' to make the cargo cache persistent in a Docker Volume. 11 | "mounts": [ 12 | { 13 | "source": "devcontainer-cargo-cache-${devcontainerId}", 14 | "target": "/usr/local/cargo", 15 | "type": "volume" 16 | } 17 | ], 18 | 19 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 20 | "forwardPorts": [ 21 | 2375 22 | ], 23 | "customizations": { 24 | "vscode": { 25 | "extensions": [ 26 | "vadimcn.vscode-lldb", 27 | "rust-lang.rust-analyzer" 28 | ] 29 | } 30 | } 31 | 32 | // Use 'postCreateCommand' to run commands after the container is created. 33 | 34 | // Configure tool-specific properties. 35 | // "customizations": {}, 36 | 37 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 38 | // "remoteUser": "root" 39 | } -------------------------------------------------------------------------------- /src/docker/types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use serde_json::Value; 3 | use std::collections::HashMap; 4 | 5 | #[derive(Serialize, Deserialize)] 6 | pub struct DockerErrorMessage { 7 | pub message: String 8 | } 9 | 10 | #[derive(Serialize, Deserialize)] 11 | pub struct ContainerSummary { 12 | #[serde(rename = "Id")] 13 | pub id: Option, 14 | 15 | #[serde(rename = "Names")] 16 | pub names: Option>, 17 | 18 | pub message: Option, 19 | 20 | #[serde(rename = "Labels")] 21 | pub labels: Option>, 22 | 23 | #[serde(flatten)] 24 | extra: HashMap, 25 | } 26 | 27 | #[derive(Serialize, Deserialize)] 28 | pub struct ContainerInspect { 29 | #[serde(rename = "Id")] 30 | pub id: Option, 31 | 32 | #[serde(rename = "Name")] 33 | pub name: Option, 34 | 35 | #[serde(rename = "Config")] 36 | pub config: Option, 37 | 38 | pub message: Option, 39 | 40 | #[serde(flatten)] 41 | extra: HashMap, 42 | } 43 | 44 | #[derive(Serialize, Deserialize)] 45 | pub struct ContainerConfig { 46 | #[serde(rename = "Env")] 47 | pub env: Option>, 48 | #[serde(rename = "Labels")] 49 | pub labels: Option>, 50 | 51 | #[serde(flatten)] 52 | extra: HashMap, 53 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "type": "lldb", 10 | "request": "launch", 11 | "name": "Debug executable 'docker-proxy-filter'", 12 | "cargo": { 13 | "args": [ 14 | "build", 15 | "--bin=docker-proxy-filter", 16 | "--package=docker-proxy-filter" 17 | ], 18 | "filter": { 19 | "name": "docker-proxy-filter", 20 | "kind": "bin" 21 | } 22 | }, 23 | "args": [], 24 | "cwd": "${workspaceFolder}" 25 | }, 26 | { 27 | "type": "lldb", 28 | "request": "launch", 29 | "name": "Debug unit tests in executable 'docker-proxy-filter'", 30 | "cargo": { 31 | "args": [ 32 | "test", 33 | "--no-run", 34 | "--bin=docker-proxy-filter", 35 | "--package=docker-proxy-filter" 36 | ], 37 | "filter": { 38 | "name": "docker-proxy-filter", 39 | "kind": "bin" 40 | } 41 | }, 42 | "args": [], 43 | "cwd": "${workspaceFolder}" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::config::ContainerLabels; 2 | use std::collections::HashMap; 3 | use tracing::*; 4 | 5 | pub fn strings_in_strings(ref_strings: &Vec, contains_strings: &Vec) -> bool { 6 | let matched_str = ref_strings.iter().find(|x| contains_strings.iter().any(|y| { 7 | let contains = x.contains(y); 8 | if contains { 9 | debug!("'{}' found in {}", y, x); 10 | } 11 | contains 12 | })); 13 | 14 | matched_str.is_some() 15 | } 16 | 17 | pub fn label_match(ref_map: &HashMap, contains_map: &ContainerLabels) -> bool { 18 | if contains_map.is_empty() { 19 | return true 20 | } 21 | if ref_map.is_empty() { 22 | return false 23 | } 24 | 25 | for(k, v) in ref_map.iter() { 26 | if contains_map.iter().any(|(ck, cv)| { 27 | if k.contains(ck) { 28 | let val_match = match cv { 29 | Some(val) => { 30 | if v.contains(val) { 31 | debug!("Label {}={} contains label key filter '{}' and label value filter '{}'", k,v, ck, val); 32 | return true; 33 | } 34 | false 35 | } 36 | None => { 37 | debug!("Label {}={} contains label key filter '{}'", k,v, ck); 38 | true 39 | } 40 | }; 41 | return val_match 42 | } 43 | return false 44 | }) { 45 | return true 46 | } 47 | } 48 | 49 | return false 50 | } 51 | 52 | pub fn short_id(s: &String) -> String { 53 | return format!("{start}...{end}", start = &s[..6], end = &s[s.len() - 6..]); 54 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use tracing::*; 2 | use ntex::{http, web::{self}}; 3 | use std::sync::{Arc, Mutex}; 4 | 5 | use std::collections::HashMap; 6 | 7 | mod config; 8 | mod docker; 9 | mod proxy; 10 | mod utils; 11 | 12 | use proxy::{AppStateWithContainerMap}; 13 | 14 | #[ntex::main] 15 | async fn main() -> std::io::Result<()> { 16 | 17 | match config::loadenv() { 18 | Ok(_) => (), 19 | Err(err) => { 20 | println!("there was a problem reading .env: {err}"); 21 | } 22 | } 23 | 24 | tracing_subscriber::fmt::fmt() 25 | // uses RUST_LOG env for filtering log levels and namespaces 26 | .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) 27 | .init(); 28 | 29 | let (config, port) = match config::get_config() { 30 | Ok((config, port)) => { 31 | (config, port) 32 | }, 33 | Err(_error) => { 34 | panic!("Unable to start due to invalid envs") 35 | } 36 | }; 37 | 38 | if config.container_labels.is_empty() && config.container_names.is_empty() { 39 | warn!("You have not defined any filters! All containers will be exposed. If you are using docker-proxy-filter only for SCRUB_ENVS then this is expected behavior, otherwise check your environmental variables."); 40 | } 41 | 42 | let cm = AppStateWithContainerMap { 43 | container_map: Arc::new(Mutex::new(HashMap::>::new())) 44 | }; 45 | 46 | let forward_url = url::Url::parse(&config.proxy_url) 47 | .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; 48 | web::server(move || { 49 | web::App::new() 50 | .state(http::Client::new()) 51 | .state(forward_url.clone()) 52 | .state(config.container_names.clone()) 53 | .state(cm.clone()) 54 | .state(config.scrub_envs.clone()) 55 | .state(config.clone()) 56 | 57 | .wrap(web::middleware::Logger::default()) 58 | .default_service(web::route().to(proxy::forward)) 59 | }) 60 | .bind(("0.0.0.0", port))? 61 | .run() 62 | .await 63 | } 64 | -------------------------------------------------------------------------------- /.devcontainer/compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | # Update this to the name of the service you want to work with in your docker-compose.yml file 4 | dev: 5 | # Uncomment if you want to override the service's Dockerfile to one in the .devcontainer 6 | # folder. Note that the path of the Dockerfile and context is relative to the *primary* 7 | # docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile" 8 | # array). The sample below assumes your primary file is in the root of your project. 9 | # 10 | # build: 11 | # context: . 12 | # dockerfile: .devcontainer/Dockerfile 13 | 14 | image: "mcr.microsoft.com/devcontainers/rust:1-1-bookworm" 15 | 16 | volumes: 17 | # Update this to wherever you want VS Code to mount the folder of your project 18 | - ..:/workspaces:cached 19 | command: sleep infinity 20 | 21 | socket-proxy: 22 | image: wollomatic/socket-proxy:1.10.0 23 | restart: unless-stopped 24 | user: 0:0 25 | mem_limit: 64M 26 | read_only: true 27 | ports: 28 | - 2379:2375 29 | cap_drop: 30 | - ALL 31 | security_opt: 32 | - no-new-privileges 33 | command: 34 | # - '-loglevel=info' 35 | 36 | - '-loglevel=debug' 37 | - '-allowGET=.*' 38 | - '-allowHEAD=.*' 39 | - '-allowPOST=.*' 40 | - '-allowPUT=.*' 41 | - '-allowPATCH=.*' 42 | - '-allowDELETE=.*' 43 | - '-allowCONNECT=.*' 44 | - '-allowTRACE=.*' 45 | - '-allowOPTIONS=.*' 46 | 47 | - '-listenip=0.0.0.0' 48 | - '-allowfrom=0.0.0.0/0' 49 | 50 | #- '-allowGET=/_ping|v1\..{1,2}/(info|containers/json|events)' 51 | #- '-allowGET=/v1\..{1,2}/(version|containers/.*|events.*)' 52 | - '-allowbindmountfrom=/var/log,/tmp' # restrict bind mounts to specific directories 53 | - '-watchdoginterval=3600' # check once per hour for socket availability 54 | - '-stoponwatchdog' # halt program on error and let compose restart it 55 | - '-shutdowngracetime=5' # wait 5 seconds before shutting down 56 | volumes: 57 | - /var/run/docker.sock:/var/run/docker.sock:ro -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use tracing::*; 3 | use std::collections::HashMap; 4 | 5 | fn default_scrub() -> bool { 6 | false 7 | } 8 | fn default_port() -> u16 { 9 | 2375 10 | } 11 | fn default_list() -> Vec { 12 | Vec::new() 13 | } 14 | 15 | #[derive(Deserialize, Debug, Clone)] 16 | pub struct EnvConfig { 17 | pub proxy_url: String, 18 | #[serde(default = "default_list")] 19 | pub container_names: Vec, 20 | #[serde(default = "default_list")] 21 | pub container_labels: Vec, 22 | #[serde(default = "default_scrub")] 23 | pub scrub_envs: bool, 24 | #[serde(default = "default_port")] 25 | pub port: u16, 26 | } 27 | 28 | pub type ContainerLabels = HashMap>; 29 | pub type ContainerNames = Vec; 30 | 31 | #[derive(Clone)] 32 | pub struct AppConfig { 33 | pub proxy_url: String, 34 | pub container_names: ContainerNames, 35 | pub scrub_envs: bool, 36 | pub container_labels: ContainerLabels 37 | } 38 | 39 | impl From<&EnvConfig> for AppConfig { 40 | fn from(item: &EnvConfig) -> Self { 41 | 42 | let mut label_map: ContainerLabels = HashMap::>::new(); 43 | for label_kv in item.container_labels.iter() { 44 | if let Some((k, v)) = label_kv.split_once('=') { 45 | label_map.insert(k.to_string(), Some(v.to_string())); 46 | } else { 47 | label_map.insert(label_kv.clone(), None); 48 | } 49 | } 50 | 51 | AppConfig { 52 | proxy_url: item.proxy_url.clone(), 53 | container_names: item.container_names.clone(), 54 | scrub_envs: item.scrub_envs, 55 | container_labels: label_map.clone() 56 | } 57 | } 58 | } 59 | 60 | pub fn loadenv() -> Result<(), dotenvy::Error> { 61 | match dotenvy::dotenv() { 62 | Ok(_) => Ok(()), 63 | Err(err) => { 64 | // we don't care if there isn't a .env file 65 | if err.not_found() { 66 | Ok(()) 67 | } else { 68 | Err(err) 69 | } 70 | } 71 | } 72 | } 73 | 74 | pub fn get_config() -> Result<(AppConfig, u16), envy::Error> { 75 | match envy::from_env::() { 76 | Ok(config) => { 77 | info!("{:#?}", config); 78 | Ok((AppConfig::from(&config), config.port)) 79 | } 80 | Err(error) => { 81 | error!("Could not parse envs correctly! {:#?}", error); 82 | Err(error) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /usecases.md: -------------------------------------------------------------------------------- 1 | # Usecases 2 | 3 | Some common uses for Docker Proxy Filter with popular applications. 4 | 5 | ## Homepage Docker Integration 6 | 7 | [Homepage](https://gethomepage.dev/), a popular startpage application, can [use the Docker API](https://gethomepage.dev/configs/docker/) to discover services automatically for its dashboard. 8 | 9 | Homepage uses only the `/containers/json` endpoint to find services by label and parse running state. There is no need for it to have access to other non-homepage labeled services. 10 | 11 | Use the [`CONTAINER_LABELS`](/README.md#container_labels) environmental to allow any label with a key containing `homepage`: 12 | 13 | ```yaml 14 | services: 15 | proxy-container: 16 | image: foxxmd/docker-proxy-filter 17 | environment: 18 | - PROXY_URL=http://socket-proxy:2375 19 | - CONTAINER_LABELS=homepage 20 | ports: 21 | - 2375:2375 22 | socket-proxy: 23 | image: wollomatic/socket-proxy:1.10.0 24 | restart: unless-stopped 25 | user: 0:0 26 | mem_limit: 64M 27 | read_only: true 28 | cap_drop: 29 | - ALL 30 | security_opt: 31 | - no-new-privileges 32 | command: 33 | - '-loglevel=debug' 34 | - '-listenip=0.0.0.0' 35 | - '-allowfrom=proxy-container' 36 | - '-allowHEAD=/_ping' 37 | - '-allowGET=/_ping|/(v1\..{1,2}/)?(info|version|containers|events).*' 38 | volumes: 39 | - /var/run/docker.sock:/var/run/docker.sock:ro 40 | ``` 41 | 42 | ## Uptime Kuma Docker Monitor 43 | 44 | [Uptime Kuma](https://github.com/louislam/uptime-kuma) can create [monitors for Docker containers](https://github.com/louislam/uptime-kuma/wiki/How-to-Monitor-Docker-Containers) by using the Docker API through either direct socket connection or TCP/HTTP. 45 | 46 | In Uptime Kuma, setup a new Docker Host using docker-proxy-filter instead of a normal socket-proxy. Then, add a label (`uptime.enabled=true`) on for each service you want Uptime Kuma to be able to monitor. Finally, add that label to `CONTAINER_LABELS` for docker-proxy-filter. 47 | 48 | ```yaml 49 | services: 50 | proxy-container: 51 | image: foxxmd/docker-proxy-filter 52 | environment: 53 | - PROXY_URL=http://socket-proxy:2375 54 | - CONTAINER_LABELS=uptime.enabled=true 55 | ports: 56 | - 2375:2375 57 | socket-proxy: 58 | image: wollomatic/socket-proxy:1.10.0 59 | restart: unless-stopped 60 | user: 0:0 61 | mem_limit: 64M 62 | read_only: true 63 | cap_drop: 64 | - ALL 65 | security_opt: 66 | - no-new-privileges 67 | command: 68 | - '-loglevel=debug' 69 | - '-listenip=0.0.0.0' 70 | - '-allowfrom=proxy-container' 71 | - '-allowHEAD=/_ping' 72 | - '-allowGET=/_ping|/(v1\..{1,2}/)?(info|version|containers|events).*' 73 | volumes: 74 | - /var/run/docker.sock:/var/run/docker.sock:ro 75 | ``` -------------------------------------------------------------------------------- /src/docker.rs: -------------------------------------------------------------------------------- 1 | use std::sync::LazyLock; 2 | use regex::Regex; 3 | use std::collections::HashMap; 4 | 5 | use crate::config::{ContainerLabels, ContainerNames}; 6 | use crate::utils; 7 | 8 | use ntex::{http::{self}, web::{self}}; 9 | 10 | pub mod types; 11 | 12 | pub struct GetMatch { 13 | pub id: String, 14 | pub resource: String 15 | } 16 | 17 | pub fn match_container_get(haystack: &str) -> Option { 18 | static RE: LazyLock = LazyLock::new(|| Regex::new(r"containers/(?.+)/(?.+)").unwrap()); 19 | let captures = RE.captures(haystack); 20 | 21 | match captures { 22 | Some(cap) => { 23 | Some(GetMatch { 24 | id: String::from(cap.name("id").unwrap().as_str()), 25 | resource: String::from(cap.name("resource").unwrap().as_str()) 26 | }) 27 | } 28 | None => { 29 | None 30 | } 31 | } 32 | } 33 | 34 | pub fn match_labels_or_names(filter_names: &ContainerNames, filter_labels: &ContainerLabels, names: &Vec, labels: &HashMap) -> bool { 35 | if filter_names.is_empty() && filter_labels.is_empty() { 36 | return true 37 | } 38 | if !filter_names.is_empty() { 39 | if utils::strings_in_strings(&names, &filter_names) { 40 | return true; 41 | } 42 | } 43 | if !filter_labels.is_empty() { 44 | if utils::label_match(&labels, &filter_labels) { 45 | return true; 46 | } 47 | } 48 | false 49 | } 50 | 51 | pub fn container_summary_match(container: &types::ContainerSummary, container_names: &ContainerNames, container_labels: &ContainerLabels) -> bool { 52 | 53 | return match_labels_or_names(container_names, container_labels, &container.names.as_ref().unwrap_or(Vec::new().as_ref()), &container.labels.as_ref().unwrap_or(&HashMap::::new())) 54 | } 55 | 56 | pub async fn get_container_info(client: &web::types::State, u: &web::types::State, container_id: &String) -> Result<(String, HashMap), Box> { 57 | 58 | let mut uri = u.get_ref().clone(); 59 | uri.set_path(format!("containers/{id}/json", id = container_id).as_str()); 60 | 61 | let mut res = client.get(uri.to_string()) 62 | .send() 63 | .await; 64 | // .map_err(web::Error::from)?; 65 | 66 | match res { 67 | Ok(mut okres) => { 68 | let info_res = okres.json::() 69 | .limit(2097152).await; 70 | match info_res { 71 | Ok(json_res) => { 72 | if json_res.message.is_some() { 73 | return Err(json_res.message.unwrap().into()) 74 | } 75 | Ok((json_res.name.expect("Container has a name"), json_res.config.expect("Container has config").labels.expect("Container has labels"))) 76 | }, 77 | Err(e) => { 78 | return Err(Box::new(e)); 79 | } 80 | } 81 | }, 82 | Err(e) => { 83 | return Err(Box::new(e)); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Proxy Filter 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Docker Pulls](https://img.shields.io/docker/pulls/foxxmd/docker-proxy-filter)](https://hub.docker.com/r/foxxmd/docker-proxy-filter) 5 | 6 | Docker Proxy Filter (DPF) is a smol, forward proxy for **filtering the _content_ and _responses_** of Docker API responses to only those you want to expose. 7 | 8 | Unlike the OG [docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) and its variants, DPF provides filtering of the _response content_ from the Docker API, rather than disabling/enabling of API endpoints. 9 | 10 | It does not connect directly to the Docker socket: it designed to be used with another Docker "Socket Proxy" container. 11 | 12 | Combined with a socket-proxy container that provides granular endpoint access it's possible to expose only information about specific containers in a read-only context. 13 | 14 | [**Read the blog post**](https://blog.foxxmd.dev/posts/restricting-socket-proxy-by-container/) explaining why DPF is needed and how to use it, or check out [**Use Cases**](/usecases.md) for some common scenarios with popular apps where DPF can come in handy. 15 | 16 | ## Features 17 | 18 | ### Container Filtering 19 | 20 | DPF can modify the responses returned from the Docker API for any [Container related endpoint](https://docs.docker.com/reference/api/engine/version/v1.48/#tag/Container): 21 | 22 | * Filters [List Containers](https://docs.docker.com/reference/api/engine/version/v1.48/#tag/Container/operation/ContainerList) responses so any container that does not match filters is excluded from the return list 23 | * Any other [Container](https://docs.docker.com/reference/api/engine/version/v1.48/#tag/Container) endpoints will return 404 if it does not match a filter 24 | 25 | #### Filters 26 | 27 | If a container matches **any** of these filters then it is valid and will be returned. 28 | 29 | ##### `CONTAINER_NAMES` 30 | 31 | A comma-delimited list of values that a Container's name may include. Any value that matches will cause a Container to be valid. 32 | 33 | Example 34 | 35 | ``` 36 | CONTAINER_NAMES=foo,bar 37 | 38 | Containers: 39 | 40 | * myproject-foo-1 <-- valid 41 | * coolthingbar-2 <-- valid 42 | * other-container <-- invalid 43 | ``` 44 | 45 | ##### `CONTAINER_LABELS` 46 | 47 | A comma-delimited list of labels with optional values (key-value) that any of a Container's labels may include. Any value that matches will cause a Container to be valid. 48 | 49 | * If a filter is **only** a key (no `=`) then any Container label key that includes the string will match, regardless of value 50 | * If a filter is a full key-value (`my.label=value`) then 51 | * Container label key must include filter key 52 | * Container label value must include filter value 53 | 54 | Example 55 | 56 | ``` 57 | CONTAINER_LABELS=myfoo,com.bar=fun 58 | 59 | Container A's labels 60 | * something=cool <-- invalid 61 | * com.something=nice <-- invalid 62 | * com.bar=fun <-- valid 63 | 64 | Container B's labels 65 | * something=cool <-- invalid 66 | * com.myfoo.aaa=yo <-- valid 67 | * com.myfoo.bbb=hey <-- valid 68 | * com.bar=sad <-- invalid 69 | ``` 70 | 71 | #### `SCRUB_ENVS` Modifier 72 | 73 | When `true` any responses from the [Container Inspect](https://docs.docker.com/reference/api/engine/version/v1.48/#tag/Container/operation/ContainerInspect) endpoint will have `Config.Env` set to an empty array. This prevents leaking of sensitive `environment:`/`-e` variables that you passed to your container, over the network. 74 | 75 | ### More? 76 | 77 | If I find use cases for filtering other endpoints they will be implemented in the future! Open a new Issue if you have ideas. 78 | 79 | ## Install 80 | 81 | Docker images are available for x86/ARMv7 hosts: 82 | 83 | ``` 84 | docker.io/foxxmd/docker-proxy-filter:latest 85 | ghcr.io/foxxmd/docker-proxy-filter:latest 86 | ``` 87 | 88 | The proxy server is available on port `2375` within the deployed container. 89 | 90 | ## Example 91 | 92 | ```yaml 93 | services: 94 | proxy-filter: 95 | image: foxxmd/docker-proxy-filter 96 | environment: 97 | - PROXY_URL=http://socket-proxy:2375 98 | - CONTAINER_NAME=foo,bar 99 | - SCRUB_ENVS=true 100 | ports: 101 | - 2375:2375 102 | socket-proxy: 103 | image: wollomatic/socket-proxy:1.10.0 104 | restart: unless-stopped 105 | user: 0:0 106 | mem_limit: 64M 107 | read_only: true 108 | cap_drop: 109 | - ALL 110 | security_opt: 111 | - no-new-privileges 112 | command: 113 | - '-loglevel=debug' 114 | - '-allowGET=/_ping|/(v1\..{1,2}/)?(info|version|containers|events).*' 115 | - '-allowHEAD=/_ping' 116 | - '-listenip=0.0.0.0' 117 | - '-allowfrom=proxy-filter' 118 | - '-stoponwatchdog' 119 | - '-shutdowngracetime=5' 120 | volumes: 121 | - /var/run/docker.sock:/var/run/docker.sock:ro 122 | ``` 123 | 124 | On your machine you are running these containers: 125 | 126 | 127 | | Id | Name | 128 | |------|--------------| 129 | | 1234 | foo | 130 | | abcd | bar | 131 | | 6969 | cool-program | 132 | | 0444 | fun-program | 133 | 134 | ```shell 135 | $ curl -i http://localhost:2375/v1.47/containers 136 | HTTP/1.1 200 OK 137 | content-length: 1234 138 | content-type: application/json 139 | date: Wed, 08 Oct 2025 00:33:02 GMT 140 | 141 | [{"Id": 1234, "Names": ["/foo"] ...},{"Id": "abcd": "Names": ["/bar"]}] 142 | # cool-program and fun-program have been filtered out of array 143 | ``` 144 | 145 | ```shell 146 | $ curl -i http://localhost:2375/v1.47/containers/6969/json 147 | HTTP/1.1 404 Not Found 148 | transfer-encoding: chunked 149 | content-type: application/json 150 | date: Wed, 08 Oct 2025 00:30:54 GMT 151 | 152 | {"message":"No such container: 6969"} 153 | # returns 404 as if no container is running 154 | ``` 155 | 156 | ```shell 157 | $ curl -i http://localhost:2375/v1.47/containers/1234/json 158 | HTTP/1.1 404 Not Found 159 | transfer-encoding: chunked 160 | content-type: application/json 161 | date: Wed, 08 Oct 2025 00:30:54 GMT 162 | 163 | {"Id": 1234, "Name": "/foo" ...} 164 | # returns container because Name is substring of CONTAINER_NAME values 165 | ``` 166 | 167 | ```shell 168 | $ curl -i http://localhost:2375/v1.47/volumes 169 | HTTP/1.1 403 Forbidden 170 | transfer-encoding: chunked 171 | content-type: text/plain 172 | date: Wed, 08 Oct 2025 00:39:59 GMT 173 | 174 | Forbidden 175 | # not allowed by wollomatic/socket-proxy config 176 | ``` 177 | 178 | ## Configuration 179 | 180 | All configuration is done through environmental variables. 181 | 182 | | Key | Required | Default | Description | 183 | |--------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| 184 | | `PROXY_URL` | yes | | The fully-qualified URL to proxy API requests EX `http://socket-proxy:2375` | 185 | | `CONTAINER_NAMES` | no | | A comma-delimited list of values to compare against a container name. | 186 | | `CONTAINER_LABELS` | no | | A comma-delimited list of key-values to compare against container labels. | 187 | | `SCRUB_ENVS` | no | false | Remove `Env` list from [container inspect API](https://docs.docker.com/reference/api/engine/version/v1.48/#tag/Container/operation/ContainerInspect) response | 188 | 189 | -------------------------------------------------------------------------------- /src/proxy.rs: -------------------------------------------------------------------------------- 1 | use tracing::*; 2 | use std::sync::{Arc, Mutex}; 3 | use std::collections::HashMap; 4 | use ntex::{http::{self, HttpMessage}, web::{self}}; 5 | use futures_util::TryStreamExt; 6 | use ::http::StatusCode; 7 | 8 | use crate::config::{AppConfig}; 9 | use crate::docker::{self, types::*}; 10 | use crate::utils; 11 | 12 | #[derive(Clone)] 13 | pub struct AppStateWithContainerMap { 14 | pub container_map: Arc>>>, // <- Mutex is necessary to mutate safely across threads 15 | } 16 | 17 | macro_rules! is { 18 | ($cond:expr; $if:expr; $else:expr) => { 19 | if $cond { $if } else { $else } 20 | }; 21 | } 22 | 23 | pub async fn forward( 24 | req: web::HttpRequest, 25 | body: ntex::util::Bytes, 26 | client: web::types::State, 27 | forward_url: web::types::State, 28 | app_config: web::types::State, 29 | data: web::types::State 30 | ) -> Result { 31 | let mut new_url = forward_url.get_ref().clone(); 32 | new_url.set_path(req.uri().path()); 33 | new_url.set_query(req.uri().query()); 34 | let forwarded_req = client.request_from(new_url.as_str(), req.head()); 35 | let mut res = forwarded_req 36 | .send_body(body) 37 | .await 38 | .map_err(web::Error::from)?; 39 | 40 | let mut client_resp = web::HttpResponse::build(res.status()); 41 | client_resp.content_type(res.content_type()); 42 | 43 | if res.status() == 200 { 44 | 45 | // if route is to list containers we want to return a filtered list 46 | if new_url.path().contains("containers/json") { 47 | let _list_span = span!(Level::DEBUG, "Container List").entered(); 48 | 49 | let container_res = &res.json::>() 50 | // 2mb in bytes 51 | .limit(2097152).await; 52 | 53 | let containers = match container_res { 54 | Ok(list_res) => { 55 | list_res 56 | } 57 | Err(e) => { 58 | panic!("{e}"); 59 | } 60 | }; 61 | 62 | // filter all containers to only those that have values from CONTAINER_NAMES includes in their names 63 | let filtered_containers = containers.into_iter() 64 | .filter(|&con| { 65 | let _list_span = span!(Level::DEBUG, "Container", id = utils::short_id(con.id.as_ref().unwrap())).entered(); 66 | docker::container_summary_match(con, &app_config.get_ref().container_names, &app_config.get_ref().container_labels) 67 | }) 68 | .collect::>(); 69 | 70 | let fresp = web::HttpResponse::build(res.status()).json(&filtered_containers); 71 | debug!("{} of {} containers valid", filtered_containers.len(), containers.len()); 72 | Ok(fresp) 73 | } else { 74 | 75 | // only deal with routes that are for containers like /containers/1234/{some_resource} 76 | match docker::match_container_get(new_url.path()) { 77 | // the regex pulls the container id from the route with a named capture group, avaiable as m.id 78 | 79 | Some (m) => { 80 | let short_cid = utils::short_id(&m.id); //format!("{start}...{end}", start = &m.id[..6], end = &m.id[&m.id.len() - 6..]); 81 | let _con_span = span!(Level::DEBUG, "Container", id = short_cid).entered(); 82 | debug!("Matched container route with Id {}", &m.id); 83 | // we keep a stateful hashmap of all requested container ids and their names 84 | // see AppStateWithContainerMap 85 | let mut cm = data.container_map.lock().unwrap(); 86 | 87 | // if the map does not already include the container id-name then we try to get it with our own request to docker api 88 | // or if we encountered an error last time then try again 89 | if !cm.contains_key(&m.id) || cm.get(&m.id).unwrap().is_none() { 90 | debug!("Requested Id not in map, trying to inspect..."); 91 | let info_res = docker::get_container_info(&client, &forward_url, &m.id).await; 92 | match info_res { 93 | Ok((name, labels)) => { 94 | let is_container_match = docker::match_labels_or_names(&app_config.get_ref().container_names, &app_config.get_ref().container_labels, &Vec::from([name.clone()]), &labels); 95 | debug!("Recording container '{}' {} valid", name, is!(is_container_match; "as";"as not")); 96 | cm.insert(m.id.clone(), Some(is_container_match)); 97 | } 98 | Err(e) => { 99 | warn!("Could not inspect: {e}"); 100 | if e.to_string().contains("No such container") { 101 | cm.insert(m.id.clone(), Some(false)); 102 | } else { 103 | // if the error was not a 404 then allow trying again later 104 | cm.insert(m.id.clone(), None); 105 | } 106 | } 107 | } 108 | } 109 | 110 | // then we try to get the name from the stateful hashmap 111 | let allowed = cm.get(&m.id).unwrap(); 112 | 113 | match allowed { 114 | Some(n) => { 115 | // only return if a response if requested container has a name that includes values from CONTAINER_NAMES 116 | if *n { 117 | debug!("Matched container filters"); 118 | // if the route resource is specifically the Container Inspect API 119 | // then we may need to scrub Envs if SCRUB_ENVS=true 120 | if m.resource == "json" { 121 | 122 | client_resp.content_type("application/json"); 123 | 124 | if app_config.get_ref().scrub_envs { 125 | let mut container = res.json::().await.unwrap(); 126 | container.config.as_mut().unwrap().env = Some(Vec::new()); 127 | Ok(client_resp.json(&container)) 128 | } else { 129 | Ok(client_resp.streaming(res.into_stream())) 130 | } 131 | 132 | } else { 133 | client_resp.content_type(res.content_type()); 134 | Ok(client_resp.streaming(res.into_stream())) 135 | } 136 | } else { 137 | debug!("Does not match container filters, 404ing..."); 138 | client_resp.status(StatusCode::NOT_FOUND); 139 | Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 140 | } 141 | } 142 | None => { 143 | debug!("Does not exist or Docker API previously returned an error, 404ing..."); 144 | client_resp.status(StatusCode::NOT_FOUND); 145 | Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 146 | } 147 | } 148 | } 149 | // if we don't match container route then proxy response through, unmodified 150 | None => { 151 | let stream = res.into_stream(); 152 | Ok(client_resp.streaming(stream)) 153 | } 154 | } 155 | } 156 | 157 | } else { 158 | let stream = res.into_stream(); 159 | Ok(client_resp.streaming(stream)) 160 | } 161 | 162 | 163 | } -------------------------------------------------------------------------------- /.github/workflows/publishImage.yml: -------------------------------------------------------------------------------- 1 | # Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners 2 | 3 | name: Publish Docker image to Dockerhub 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | on: 10 | workflow_dispatch: 11 | push: 12 | branches: 13 | - 'main' 14 | tags: 15 | - '*.*.*' 16 | # don't trigger if just updating docs 17 | paths-ignore: 18 | - '*.md' 19 | - '.github/**' 20 | - '.vscode/**' 21 | - '.devcontainer/**' 22 | # use release instead of tags once version is correctly parsed 23 | # https://github.com/docker/metadata-action/issues/422 24 | # https://github.com/docker/metadata-action/issues/240 25 | # release: 26 | # types: [ published ] 27 | 28 | # define in GH Repository -> Actions -> Variables (or act .variables) to enable pushing to registries 29 | # -- will only push to registries that are defined 30 | # EX 31 | # DOCKERHUB_SLUG=foxxmd/multi-scrobbler 32 | # GHCR_SLUG=ghcr.io/foxxmd/multi-scrobbler 33 | 34 | jobs: 35 | 36 | build: 37 | name: Build OCI Images 38 | if: ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }} 39 | runs-on: ${{ matrix.os }} 40 | permissions: 41 | packages: write 42 | contents: read 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | include: 47 | - os: ubuntu-latest 48 | arch: amd64 49 | platform: linux/amd64 50 | - os: ubuntu-24.04-arm 51 | arch: arm64 52 | platform: linux/arm64 53 | steps: 54 | - name: Prepare 55 | run: | 56 | platform=${{ matrix.platform }} 57 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 58 | 59 | # list all registries to push to and join all non-empty with comma 60 | # https://unix.stackexchange.com/a/693165/116849 61 | # https://stackoverflow.com/a/9429887/1469797 62 | strings=("${{vars.DOCKERHUB_SLUG}}" "${{vars.GHCR_SLUG}}") 63 | for i in ${!strings[@]}; do [[ -z ${strings[i]} ]] && unset strings[i]; done 64 | joined_string=$(IFS=, ; echo "${strings[*]}") 65 | echo "REGISTRIES_JOINED=$joined_string" >> $GITHUB_ENV 66 | 67 | - name: Check out the repo 68 | uses: actions/checkout@v4 69 | 70 | - name: Set short git commit SHA 71 | id: appvars 72 | # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7 73 | # short sha available under env.COMMIT_SHORT_SHA 74 | run: | 75 | calculatedSha=$(git rev-parse --short HEAD) 76 | branchName=$(git rev-parse --abbrev-ref HEAD) 77 | echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV 78 | echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV 79 | 80 | - name: Get App Version 81 | id: appversion 82 | env: 83 | # use release instead of tags once version is correctly parsed 84 | #APP_VERSION: ${{ github.event.release.tag_name }} 85 | 86 | # https://github.com/actions/runner/issues/409#issuecomment-752775072 87 | # https://stackoverflow.com/a/69919067/1469797 88 | APP_VERSION: ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }} 89 | run: | 90 | echo appversion=$APP_VERSION >>${GITHUB_OUTPUT} 91 | 92 | - name: Login to Docker Hub 93 | if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }} 94 | uses: docker/login-action@v3 95 | with: 96 | username: ${{ secrets.DOCKER_USERNAME }} 97 | password: ${{ secrets.DOCKER_PASSWORD }} 98 | 99 | - name: Login to GitHub Container Registry 100 | if: ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }} 101 | uses: docker/login-action@v3 102 | with: 103 | registry: ghcr.io 104 | username: ${{ github.repository_owner }} 105 | password: ${{ secrets.GITHUB_TOKEN }} 106 | 107 | # metadata extract for docker labels/image names is done in merge job 108 | 109 | - name: Set up Docker Buildx 110 | uses: docker/setup-buildx-action@v3 111 | 112 | # https://github.com/docker/build-push-action/issues/671#issuecomment-1619353328 113 | # for caching 114 | - name: Build and push by digest 115 | id: build 116 | uses: docker/build-push-action@v6 117 | with: 118 | context: . 119 | file: ./docker/Dockerfile 120 | build-args: | 121 | APP_BUILD_VERSION=${{steps.appversion.outputs.appversion}} 122 | SOURCE=${{inputs.pip_source}} 123 | platforms: ${{ matrix.platform }} 124 | labels: ${{ steps.meta.outputs.labels }} 125 | outputs: type=image,"name=${{ env.REGISTRIES_JOINED }}",push-by-digest=true,name-canonical=true,push=true 126 | #cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }} 127 | #cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }} 128 | 129 | - name: Export digest 130 | run: | 131 | mkdir -p /tmp/digests 132 | digest="${{ steps.build.outputs.digest }}" 133 | touch "/tmp/digests/${digest#sha256:}" 134 | 135 | - name: Upload digest 136 | uses: actions/upload-artifact@v4 137 | with: 138 | name: digests-${{ env.PLATFORM_PAIR }} 139 | path: /tmp/digests/* 140 | if-no-files-found: error 141 | retention-days: 1 142 | 143 | merge: 144 | name: Merge OCI Images and Push 145 | if: ${{ github.event_name != 'pull_request' && (vars.DOCKERHUB_SLUG != '' || vars.GHCR_SLUG != '') }} 146 | runs-on: ubuntu-latest 147 | permissions: 148 | packages: write 149 | contents: read 150 | needs: 151 | - build 152 | steps: 153 | - name: Download digests 154 | uses: actions/download-artifact@v4 155 | with: 156 | path: /tmp/digests 157 | pattern: digests-* 158 | merge-multiple: true 159 | 160 | - name: Login to Docker Hub 161 | if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_SLUG != '' }} 162 | uses: docker/login-action@v3 163 | with: 164 | username: ${{ secrets.DOCKER_USERNAME }} 165 | password: ${{ secrets.DOCKER_PASSWORD }} 166 | 167 | - name: Login to GitHub Container Registry 168 | if: ${{ github.event_name != 'pull_request' && vars.GHCR_SLUG != '' }} 169 | uses: docker/login-action@v3 170 | with: 171 | registry: ghcr.io 172 | username: ${{ github.repository_owner }} 173 | password: ${{ secrets.GITHUB_TOKEN }} 174 | 175 | - name: Set up Docker Buildx 176 | uses: docker/setup-buildx-action@v3 177 | 178 | - name: Extract metadata (tags, labels) 179 | id: meta 180 | uses: docker/metadata-action@v5 181 | with: 182 | images: | 183 | ${{ vars.DOCKERHUB_SLUG }} 184 | ${{ vars.GHCR_SLUG }} 185 | # generate Docker tags based on the following events/attributes 186 | # https://github.com/docker/metadata-action/issues/247#issuecomment-1511259674 for NOT is default branch, eventually 187 | tags: | 188 | type=edge 189 | 190 | # push with branch name as tag if not master/main 191 | type=ref,event=branch,enable=${{ !endsWith(github.ref, 'main') }} 192 | 193 | # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries 194 | type=match,pattern=\d.\d.\d$,priority=901 195 | 196 | # tag all semver (include pre-release) 197 | type=semver,pattern={{version}} 198 | # flavor: | 199 | # latest=false 200 | labels: | 201 | org.opencontainers.image.title=Docker Proxy Filter 202 | org.opencontainers.image.description=Filter respones and content from Docker API through an http socket 203 | org.opencontainers.image.vendor=FoxxMD 204 | 205 | - name: Create manifest list and push dockerhub 206 | if: ${{ vars.DOCKERHUB_SLUG != '' }} 207 | working-directory: /tmp/digests 208 | run: | 209 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 210 | $(printf '${{ vars.DOCKERHUB_SLUG }}@sha256:%s ' *) 211 | 212 | - name: Create manifest list and push gchr 213 | if: ${{ vars.GHCR_SLUG != '' }} 214 | working-directory: /tmp/digests 215 | run: | 216 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 217 | $(printf '${{ vars.GHCR_SLUG }}@sha256:%s ' *) 218 | 219 | - name: Inspect image dockerhub 220 | if: ${{ vars.DOCKERHUB_SLUG != '' }} 221 | run: | 222 | docker buildx imagetools inspect ${{ vars.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }} 223 | 224 | - name: Inspect image ghcr 225 | if: ${{ vars.GHCR_SLUG != '' }} 226 | run: | 227 | docker buildx imagetools inspect ${{ vars.GHCR_SLUG }}:${{ steps.meta.outputs.version }} -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.25.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.12" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "aho-corasick" 35 | version = "1.1.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 38 | dependencies = [ 39 | "memchr", 40 | ] 41 | 42 | [[package]] 43 | name = "async-channel" 44 | version = "2.5.0" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" 47 | dependencies = [ 48 | "concurrent-queue", 49 | "event-listener-strategy", 50 | "futures-core", 51 | "pin-project-lite", 52 | ] 53 | 54 | [[package]] 55 | name = "atomic-waker" 56 | version = "1.1.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 59 | 60 | [[package]] 61 | name = "backtrace" 62 | version = "0.3.76" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" 65 | dependencies = [ 66 | "addr2line", 67 | "cfg-if", 68 | "libc", 69 | "miniz_oxide", 70 | "object", 71 | "rustc-demangle", 72 | "windows-link", 73 | ] 74 | 75 | [[package]] 76 | name = "base64" 77 | version = "0.22.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 80 | 81 | [[package]] 82 | name = "bitflags" 83 | version = "2.9.4" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" 86 | 87 | [[package]] 88 | name = "block-buffer" 89 | version = "0.10.4" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 92 | dependencies = [ 93 | "generic-array", 94 | ] 95 | 96 | [[package]] 97 | name = "bytes" 98 | version = "1.10.1" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 101 | 102 | [[package]] 103 | name = "cfg-if" 104 | version = "1.0.3" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 107 | 108 | [[package]] 109 | name = "cfg_aliases" 110 | version = "0.2.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 113 | 114 | [[package]] 115 | name = "concurrent-queue" 116 | version = "2.5.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 119 | dependencies = [ 120 | "crossbeam-utils", 121 | ] 122 | 123 | [[package]] 124 | name = "core_affinity" 125 | version = "0.8.3" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" 128 | dependencies = [ 129 | "libc", 130 | "num_cpus", 131 | "winapi", 132 | ] 133 | 134 | [[package]] 135 | name = "cpufeatures" 136 | version = "0.2.17" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 139 | dependencies = [ 140 | "libc", 141 | ] 142 | 143 | [[package]] 144 | name = "crossbeam-utils" 145 | version = "0.8.21" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 148 | 149 | [[package]] 150 | name = "crypto-common" 151 | version = "0.1.6" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 154 | dependencies = [ 155 | "generic-array", 156 | "typenum", 157 | ] 158 | 159 | [[package]] 160 | name = "ctrlc" 161 | version = "3.5.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" 164 | dependencies = [ 165 | "dispatch", 166 | "nix", 167 | "windows-sys 0.61.2", 168 | ] 169 | 170 | [[package]] 171 | name = "digest" 172 | version = "0.10.7" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 175 | dependencies = [ 176 | "block-buffer", 177 | "crypto-common", 178 | ] 179 | 180 | [[package]] 181 | name = "dispatch" 182 | version = "0.2.0" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" 185 | 186 | [[package]] 187 | name = "displaydoc" 188 | version = "0.2.5" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 191 | dependencies = [ 192 | "proc-macro2", 193 | "quote", 194 | "syn 2.0.106", 195 | ] 196 | 197 | [[package]] 198 | name = "docker-proxy-filter" 199 | version = "0.1.0" 200 | dependencies = [ 201 | "dotenvy", 202 | "envy", 203 | "futures-util", 204 | "http", 205 | "ntex", 206 | "regex", 207 | "serde", 208 | "serde_json", 209 | "tracing", 210 | "tracing-subscriber", 211 | "url", 212 | ] 213 | 214 | [[package]] 215 | name = "dotenvy" 216 | version = "0.15.7" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 219 | 220 | [[package]] 221 | name = "encoding_rs" 222 | version = "0.8.35" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 225 | dependencies = [ 226 | "cfg-if", 227 | ] 228 | 229 | [[package]] 230 | name = "env_filter" 231 | version = "0.1.3" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" 234 | dependencies = [ 235 | "log", 236 | ] 237 | 238 | [[package]] 239 | name = "env_logger" 240 | version = "0.11.8" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" 243 | dependencies = [ 244 | "env_filter", 245 | "log", 246 | ] 247 | 248 | [[package]] 249 | name = "envy" 250 | version = "0.4.2" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" 253 | dependencies = [ 254 | "serde", 255 | ] 256 | 257 | [[package]] 258 | name = "errno" 259 | version = "0.3.14" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 262 | dependencies = [ 263 | "libc", 264 | "windows-sys 0.61.2", 265 | ] 266 | 267 | [[package]] 268 | name = "event-listener" 269 | version = "5.4.1" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" 272 | dependencies = [ 273 | "concurrent-queue", 274 | "parking", 275 | "pin-project-lite", 276 | ] 277 | 278 | [[package]] 279 | name = "event-listener-strategy" 280 | version = "0.5.4" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 283 | dependencies = [ 284 | "event-listener", 285 | "pin-project-lite", 286 | ] 287 | 288 | [[package]] 289 | name = "fnv" 290 | version = "1.0.7" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 293 | 294 | [[package]] 295 | name = "form_urlencoded" 296 | version = "1.2.2" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 299 | dependencies = [ 300 | "percent-encoding", 301 | ] 302 | 303 | [[package]] 304 | name = "futures-core" 305 | version = "0.3.31" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 308 | 309 | [[package]] 310 | name = "futures-macro" 311 | version = "0.3.31" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 314 | dependencies = [ 315 | "proc-macro2", 316 | "quote", 317 | "syn 2.0.106", 318 | ] 319 | 320 | [[package]] 321 | name = "futures-task" 322 | version = "0.3.31" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 325 | 326 | [[package]] 327 | name = "futures-timer" 328 | version = "3.0.3" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" 331 | 332 | [[package]] 333 | name = "futures-util" 334 | version = "0.3.31" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 337 | dependencies = [ 338 | "futures-core", 339 | "futures-macro", 340 | "futures-task", 341 | "pin-project-lite", 342 | "pin-utils", 343 | "slab", 344 | ] 345 | 346 | [[package]] 347 | name = "generic-array" 348 | version = "0.14.7" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 351 | dependencies = [ 352 | "typenum", 353 | "version_check", 354 | ] 355 | 356 | [[package]] 357 | name = "getrandom" 358 | version = "0.3.3" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 361 | dependencies = [ 362 | "cfg-if", 363 | "libc", 364 | "r-efi", 365 | "wasi 0.14.7+wasi-0.2.4", 366 | ] 367 | 368 | [[package]] 369 | name = "gimli" 370 | version = "0.32.3" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" 373 | 374 | [[package]] 375 | name = "hermit-abi" 376 | version = "0.5.2" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 379 | 380 | [[package]] 381 | name = "http" 382 | version = "1.3.1" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 385 | dependencies = [ 386 | "bytes", 387 | "fnv", 388 | "itoa", 389 | ] 390 | 391 | [[package]] 392 | name = "httparse" 393 | version = "1.10.1" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 396 | 397 | [[package]] 398 | name = "httpdate" 399 | version = "1.0.3" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 402 | 403 | [[package]] 404 | name = "icu_collections" 405 | version = "2.0.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 408 | dependencies = [ 409 | "displaydoc", 410 | "potential_utf", 411 | "yoke", 412 | "zerofrom", 413 | "zerovec", 414 | ] 415 | 416 | [[package]] 417 | name = "icu_locale_core" 418 | version = "2.0.0" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 421 | dependencies = [ 422 | "displaydoc", 423 | "litemap", 424 | "tinystr", 425 | "writeable", 426 | "zerovec", 427 | ] 428 | 429 | [[package]] 430 | name = "icu_normalizer" 431 | version = "2.0.0" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 434 | dependencies = [ 435 | "displaydoc", 436 | "icu_collections", 437 | "icu_normalizer_data", 438 | "icu_properties", 439 | "icu_provider", 440 | "smallvec", 441 | "zerovec", 442 | ] 443 | 444 | [[package]] 445 | name = "icu_normalizer_data" 446 | version = "2.0.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 449 | 450 | [[package]] 451 | name = "icu_properties" 452 | version = "2.0.1" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 455 | dependencies = [ 456 | "displaydoc", 457 | "icu_collections", 458 | "icu_locale_core", 459 | "icu_properties_data", 460 | "icu_provider", 461 | "potential_utf", 462 | "zerotrie", 463 | "zerovec", 464 | ] 465 | 466 | [[package]] 467 | name = "icu_properties_data" 468 | version = "2.0.1" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 471 | 472 | [[package]] 473 | name = "icu_provider" 474 | version = "2.0.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 477 | dependencies = [ 478 | "displaydoc", 479 | "icu_locale_core", 480 | "stable_deref_trait", 481 | "tinystr", 482 | "writeable", 483 | "yoke", 484 | "zerofrom", 485 | "zerotrie", 486 | "zerovec", 487 | ] 488 | 489 | [[package]] 490 | name = "idna" 491 | version = "1.1.0" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 494 | dependencies = [ 495 | "idna_adapter", 496 | "smallvec", 497 | "utf8_iter", 498 | ] 499 | 500 | [[package]] 501 | name = "idna_adapter" 502 | version = "1.2.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 505 | dependencies = [ 506 | "icu_normalizer", 507 | "icu_properties", 508 | ] 509 | 510 | [[package]] 511 | name = "io-uring" 512 | version = "0.7.10" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" 515 | dependencies = [ 516 | "bitflags", 517 | "cfg-if", 518 | "libc", 519 | ] 520 | 521 | [[package]] 522 | name = "itoa" 523 | version = "1.0.15" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 526 | 527 | [[package]] 528 | name = "lazy_static" 529 | version = "1.5.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 532 | 533 | [[package]] 534 | name = "libc" 535 | version = "0.2.176" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" 538 | 539 | [[package]] 540 | name = "linux-raw-sys" 541 | version = "0.11.0" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 544 | 545 | [[package]] 546 | name = "litemap" 547 | version = "0.8.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 550 | 551 | [[package]] 552 | name = "log" 553 | version = "0.4.28" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 556 | 557 | [[package]] 558 | name = "matchers" 559 | version = "0.2.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" 562 | dependencies = [ 563 | "regex-automata", 564 | ] 565 | 566 | [[package]] 567 | name = "memchr" 568 | version = "2.7.6" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 571 | 572 | [[package]] 573 | name = "mime" 574 | version = "0.3.17" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 577 | 578 | [[package]] 579 | name = "miniz_oxide" 580 | version = "0.8.9" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 583 | dependencies = [ 584 | "adler2", 585 | ] 586 | 587 | [[package]] 588 | name = "mio" 589 | version = "1.0.4" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 592 | dependencies = [ 593 | "libc", 594 | "wasi 0.11.1+wasi-snapshot-preview1", 595 | "windows-sys 0.59.0", 596 | ] 597 | 598 | [[package]] 599 | name = "nanorand" 600 | version = "0.8.0" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "6e3d189da485332e96ba8a5ef646a311871abd7915bf06ac848a9117f19cf6e4" 603 | 604 | [[package]] 605 | name = "nix" 606 | version = "0.30.1" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 609 | dependencies = [ 610 | "bitflags", 611 | "cfg-if", 612 | "cfg_aliases", 613 | "libc", 614 | ] 615 | 616 | [[package]] 617 | name = "ntex" 618 | version = "2.16.0" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "d4b41d1af2e11a7c29499395c2505550507749c35b29fa4a31234130abdb2285" 621 | dependencies = [ 622 | "base64", 623 | "bitflags", 624 | "encoding_rs", 625 | "env_logger", 626 | "httparse", 627 | "httpdate", 628 | "log", 629 | "mime", 630 | "nanorand", 631 | "ntex-bytes", 632 | "ntex-codec", 633 | "ntex-h2", 634 | "ntex-http", 635 | "ntex-io", 636 | "ntex-macros", 637 | "ntex-net", 638 | "ntex-router", 639 | "ntex-rt", 640 | "ntex-server", 641 | "ntex-service", 642 | "ntex-tls", 643 | "ntex-util", 644 | "percent-encoding", 645 | "pin-project-lite", 646 | "regex", 647 | "serde", 648 | "serde_json", 649 | "serde_urlencoded", 650 | "sha1", 651 | "thiserror", 652 | "variadics_please", 653 | ] 654 | 655 | [[package]] 656 | name = "ntex-bytes" 657 | version = "0.1.30" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "53d23b86ef2f4a947e29e959a61bdae71c9d52a80df02936a9992bc6dbda9ddb" 660 | dependencies = [ 661 | "bitflags", 662 | "bytes", 663 | "futures-core", 664 | "serde", 665 | ] 666 | 667 | [[package]] 668 | name = "ntex-codec" 669 | version = "0.6.2" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "69a7e111d946bb915d712df496728ca2a120b1b5643f66c580f13023bce46fda" 672 | dependencies = [ 673 | "ntex-bytes", 674 | ] 675 | 676 | [[package]] 677 | name = "ntex-h2" 678 | version = "1.13.0" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "2bfa6c16696b2b08cef057d581b67726213b71b42be69cda1977e351b9a36e5c" 681 | dependencies = [ 682 | "ahash", 683 | "bitflags", 684 | "log", 685 | "nanorand", 686 | "ntex-bytes", 687 | "ntex-codec", 688 | "ntex-http", 689 | "ntex-io", 690 | "ntex-net", 691 | "ntex-service", 692 | "ntex-util", 693 | "pin-project-lite", 694 | "thiserror", 695 | ] 696 | 697 | [[package]] 698 | name = "ntex-http" 699 | version = "0.1.15" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "61da3d6c8bec83c5481d7e36ed4cf1a8cd0edee3e2fa411290932b17549d5cf2" 702 | dependencies = [ 703 | "ahash", 704 | "futures-core", 705 | "http", 706 | "itoa", 707 | "log", 708 | "ntex-bytes", 709 | "serde", 710 | "thiserror", 711 | ] 712 | 713 | [[package]] 714 | name = "ntex-io" 715 | version = "2.14.0" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "55eb13ef2e89f799ef0395911b6365052cab4cea65a7d2ef870e39732bf346b2" 718 | dependencies = [ 719 | "bitflags", 720 | "log", 721 | "ntex-bytes", 722 | "ntex-codec", 723 | "ntex-service", 724 | "ntex-util", 725 | "pin-project-lite", 726 | ] 727 | 728 | [[package]] 729 | name = "ntex-macros" 730 | version = "0.1.4" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "7389855b7cf0a7cc4cd6748b6d31ad8d45481c9a4d6c977d289a469a362f7766" 733 | dependencies = [ 734 | "proc-macro2", 735 | "quote", 736 | "syn 1.0.109", 737 | ] 738 | 739 | [[package]] 740 | name = "ntex-net" 741 | version = "2.8.1" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "a53c65509e4e3abf6490514e98a570d4cbcdbf18628e9569a02cc1d47c1e29b9" 744 | dependencies = [ 745 | "bitflags", 746 | "cfg-if", 747 | "libc", 748 | "log", 749 | "ntex-bytes", 750 | "ntex-http", 751 | "ntex-io", 752 | "ntex-rt", 753 | "ntex-service", 754 | "ntex-tokio", 755 | "ntex-util", 756 | "thiserror", 757 | ] 758 | 759 | [[package]] 760 | name = "ntex-router" 761 | version = "0.5.3" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "bb9c68c26a87ffca54339be5f95223339db3e7bcc5d64733fef20812970a746f" 764 | dependencies = [ 765 | "http", 766 | "log", 767 | "ntex-bytes", 768 | "regex", 769 | "serde", 770 | ] 771 | 772 | [[package]] 773 | name = "ntex-rt" 774 | version = "0.4.32" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "c30a11a3017f0bf2ea00d0bd6ba8f69e52906aa8c1f894a060341056d8b1eef8" 777 | dependencies = [ 778 | "async-channel", 779 | "futures-timer", 780 | "log", 781 | "oneshot", 782 | "tokio", 783 | ] 784 | 785 | [[package]] 786 | name = "ntex-server" 787 | version = "2.8.1" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "b886e739e5101ba06f083244bda0557997521c3ddf9b8f85ca74bc2aa165aa29" 790 | dependencies = [ 791 | "async-channel", 792 | "atomic-waker", 793 | "core_affinity", 794 | "ctrlc", 795 | "log", 796 | "ntex-bytes", 797 | "ntex-net", 798 | "ntex-rt", 799 | "ntex-service", 800 | "ntex-util", 801 | "oneshot", 802 | "polling", 803 | "signal-hook", 804 | "socket2 0.5.10", 805 | ] 806 | 807 | [[package]] 808 | name = "ntex-service" 809 | version = "3.5.0" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "35dc63ff1a6d11eac0f27682997e4d8c2055b151e45e10dc1d76347b49fa52b7" 812 | dependencies = [ 813 | "slab", 814 | "version_check", 815 | ] 816 | 817 | [[package]] 818 | name = "ntex-tls" 819 | version = "2.6.1" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "08c6c64b87ddbd44a9140810712ced321d3fec149d74e9b76beef11aa3bc8110" 822 | dependencies = [ 823 | "log", 824 | "ntex-bytes", 825 | "ntex-io", 826 | "ntex-net", 827 | "ntex-service", 828 | "ntex-util", 829 | ] 830 | 831 | [[package]] 832 | name = "ntex-tokio" 833 | version = "0.5.4" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "fa57071a4136ac715146348fe7535b79266e46d165d9734ea61469c2ebaae415" 836 | dependencies = [ 837 | "log", 838 | "ntex-bytes", 839 | "ntex-io", 840 | "ntex-util", 841 | "tokio", 842 | ] 843 | 844 | [[package]] 845 | name = "ntex-util" 846 | version = "2.14.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "7811bcf3c3228631b0b20d12e5786c20c4cc76fb2d2b2733a6ab421641f81b6a" 849 | dependencies = [ 850 | "ahash", 851 | "bitflags", 852 | "futures-core", 853 | "futures-timer", 854 | "log", 855 | "ntex-bytes", 856 | "ntex-rt", 857 | "ntex-service", 858 | "pin-project-lite", 859 | "slab", 860 | "thiserror", 861 | ] 862 | 863 | [[package]] 864 | name = "nu-ansi-term" 865 | version = "0.50.1" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" 868 | dependencies = [ 869 | "windows-sys 0.52.0", 870 | ] 871 | 872 | [[package]] 873 | name = "num_cpus" 874 | version = "1.17.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" 877 | dependencies = [ 878 | "hermit-abi", 879 | "libc", 880 | ] 881 | 882 | [[package]] 883 | name = "object" 884 | version = "0.37.3" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" 887 | dependencies = [ 888 | "memchr", 889 | ] 890 | 891 | [[package]] 892 | name = "once_cell" 893 | version = "1.21.3" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 896 | 897 | [[package]] 898 | name = "oneshot" 899 | version = "0.1.11" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" 902 | 903 | [[package]] 904 | name = "parking" 905 | version = "2.2.1" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 908 | 909 | [[package]] 910 | name = "percent-encoding" 911 | version = "2.3.2" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 914 | 915 | [[package]] 916 | name = "pin-project-lite" 917 | version = "0.2.16" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 920 | 921 | [[package]] 922 | name = "pin-utils" 923 | version = "0.1.0" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 926 | 927 | [[package]] 928 | name = "polling" 929 | version = "3.11.0" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" 932 | dependencies = [ 933 | "cfg-if", 934 | "concurrent-queue", 935 | "hermit-abi", 936 | "pin-project-lite", 937 | "rustix", 938 | "windows-sys 0.61.2", 939 | ] 940 | 941 | [[package]] 942 | name = "potential_utf" 943 | version = "0.1.3" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" 946 | dependencies = [ 947 | "zerovec", 948 | ] 949 | 950 | [[package]] 951 | name = "proc-macro2" 952 | version = "1.0.101" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 955 | dependencies = [ 956 | "unicode-ident", 957 | ] 958 | 959 | [[package]] 960 | name = "quote" 961 | version = "1.0.41" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 964 | dependencies = [ 965 | "proc-macro2", 966 | ] 967 | 968 | [[package]] 969 | name = "r-efi" 970 | version = "5.3.0" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 973 | 974 | [[package]] 975 | name = "regex" 976 | version = "1.11.3" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" 979 | dependencies = [ 980 | "aho-corasick", 981 | "memchr", 982 | "regex-automata", 983 | "regex-syntax", 984 | ] 985 | 986 | [[package]] 987 | name = "regex-automata" 988 | version = "0.4.11" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" 991 | dependencies = [ 992 | "aho-corasick", 993 | "memchr", 994 | "regex-syntax", 995 | ] 996 | 997 | [[package]] 998 | name = "regex-syntax" 999 | version = "0.8.6" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" 1002 | 1003 | [[package]] 1004 | name = "rustc-demangle" 1005 | version = "0.1.26" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 1008 | 1009 | [[package]] 1010 | name = "rustix" 1011 | version = "1.1.2" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 1014 | dependencies = [ 1015 | "bitflags", 1016 | "errno", 1017 | "libc", 1018 | "linux-raw-sys", 1019 | "windows-sys 0.61.2", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "ryu" 1024 | version = "1.0.20" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1027 | 1028 | [[package]] 1029 | name = "serde" 1030 | version = "1.0.228" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1033 | dependencies = [ 1034 | "serde_core", 1035 | "serde_derive", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "serde_core" 1040 | version = "1.0.228" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1043 | dependencies = [ 1044 | "serde_derive", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "serde_derive" 1049 | version = "1.0.228" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1052 | dependencies = [ 1053 | "proc-macro2", 1054 | "quote", 1055 | "syn 2.0.106", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "serde_json" 1060 | version = "1.0.145" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 1063 | dependencies = [ 1064 | "itoa", 1065 | "memchr", 1066 | "ryu", 1067 | "serde", 1068 | "serde_core", 1069 | ] 1070 | 1071 | [[package]] 1072 | name = "serde_urlencoded" 1073 | version = "0.7.1" 1074 | source = "registry+https://github.com/rust-lang/crates.io-index" 1075 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1076 | dependencies = [ 1077 | "form_urlencoded", 1078 | "itoa", 1079 | "ryu", 1080 | "serde", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "sha1" 1085 | version = "0.10.6" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1088 | dependencies = [ 1089 | "cfg-if", 1090 | "cpufeatures", 1091 | "digest", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "sharded-slab" 1096 | version = "0.1.7" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1099 | dependencies = [ 1100 | "lazy_static", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "signal-hook" 1105 | version = "0.3.18" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" 1108 | dependencies = [ 1109 | "libc", 1110 | "signal-hook-registry", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "signal-hook-registry" 1115 | version = "1.4.6" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" 1118 | dependencies = [ 1119 | "libc", 1120 | ] 1121 | 1122 | [[package]] 1123 | name = "slab" 1124 | version = "0.4.11" 1125 | source = "registry+https://github.com/rust-lang/crates.io-index" 1126 | checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1127 | 1128 | [[package]] 1129 | name = "smallvec" 1130 | version = "1.15.1" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1133 | 1134 | [[package]] 1135 | name = "socket2" 1136 | version = "0.5.10" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 1139 | dependencies = [ 1140 | "libc", 1141 | "windows-sys 0.52.0", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "socket2" 1146 | version = "0.6.0" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" 1149 | dependencies = [ 1150 | "libc", 1151 | "windows-sys 0.59.0", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "stable_deref_trait" 1156 | version = "1.2.0" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1159 | 1160 | [[package]] 1161 | name = "syn" 1162 | version = "1.0.109" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1165 | dependencies = [ 1166 | "proc-macro2", 1167 | "quote", 1168 | "unicode-ident", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "syn" 1173 | version = "2.0.106" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 1176 | dependencies = [ 1177 | "proc-macro2", 1178 | "quote", 1179 | "unicode-ident", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "synstructure" 1184 | version = "0.13.2" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1187 | dependencies = [ 1188 | "proc-macro2", 1189 | "quote", 1190 | "syn 2.0.106", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "thiserror" 1195 | version = "2.0.17" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 1198 | dependencies = [ 1199 | "thiserror-impl", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "thiserror-impl" 1204 | version = "2.0.17" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 1207 | dependencies = [ 1208 | "proc-macro2", 1209 | "quote", 1210 | "syn 2.0.106", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "thread_local" 1215 | version = "1.1.9" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 1218 | dependencies = [ 1219 | "cfg-if", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "tinystr" 1224 | version = "0.8.1" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 1227 | dependencies = [ 1228 | "displaydoc", 1229 | "zerovec", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "tokio" 1234 | version = "1.47.1" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" 1237 | dependencies = [ 1238 | "backtrace", 1239 | "io-uring", 1240 | "libc", 1241 | "mio", 1242 | "pin-project-lite", 1243 | "signal-hook-registry", 1244 | "slab", 1245 | "socket2 0.6.0", 1246 | "windows-sys 0.59.0", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "tracing" 1251 | version = "0.1.41" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1254 | dependencies = [ 1255 | "pin-project-lite", 1256 | "tracing-attributes", 1257 | "tracing-core", 1258 | ] 1259 | 1260 | [[package]] 1261 | name = "tracing-attributes" 1262 | version = "0.1.30" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 1265 | dependencies = [ 1266 | "proc-macro2", 1267 | "quote", 1268 | "syn 2.0.106", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "tracing-core" 1273 | version = "0.1.34" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 1276 | dependencies = [ 1277 | "once_cell", 1278 | "valuable", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "tracing-log" 1283 | version = "0.2.0" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 1286 | dependencies = [ 1287 | "log", 1288 | "once_cell", 1289 | "tracing-core", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "tracing-subscriber" 1294 | version = "0.3.20" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" 1297 | dependencies = [ 1298 | "matchers", 1299 | "nu-ansi-term", 1300 | "once_cell", 1301 | "regex-automata", 1302 | "sharded-slab", 1303 | "smallvec", 1304 | "thread_local", 1305 | "tracing", 1306 | "tracing-core", 1307 | "tracing-log", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "typenum" 1312 | version = "1.19.0" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" 1315 | 1316 | [[package]] 1317 | name = "unicode-ident" 1318 | version = "1.0.19" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" 1321 | 1322 | [[package]] 1323 | name = "url" 1324 | version = "2.5.7" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 1327 | dependencies = [ 1328 | "form_urlencoded", 1329 | "idna", 1330 | "percent-encoding", 1331 | "serde", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "utf8_iter" 1336 | version = "1.0.4" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1339 | 1340 | [[package]] 1341 | name = "valuable" 1342 | version = "0.1.1" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1345 | 1346 | [[package]] 1347 | name = "variadics_please" 1348 | version = "1.1.0" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" 1351 | dependencies = [ 1352 | "proc-macro2", 1353 | "quote", 1354 | "syn 2.0.106", 1355 | ] 1356 | 1357 | [[package]] 1358 | name = "version_check" 1359 | version = "0.9.5" 1360 | source = "registry+https://github.com/rust-lang/crates.io-index" 1361 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1362 | 1363 | [[package]] 1364 | name = "wasi" 1365 | version = "0.11.1+wasi-snapshot-preview1" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1368 | 1369 | [[package]] 1370 | name = "wasi" 1371 | version = "0.14.7+wasi-0.2.4" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" 1374 | dependencies = [ 1375 | "wasip2", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "wasip2" 1380 | version = "1.0.1+wasi-0.2.4" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 1383 | dependencies = [ 1384 | "wit-bindgen", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "winapi" 1389 | version = "0.3.9" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1392 | dependencies = [ 1393 | "winapi-i686-pc-windows-gnu", 1394 | "winapi-x86_64-pc-windows-gnu", 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "winapi-i686-pc-windows-gnu" 1399 | version = "0.4.0" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1402 | 1403 | [[package]] 1404 | name = "winapi-x86_64-pc-windows-gnu" 1405 | version = "0.4.0" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1408 | 1409 | [[package]] 1410 | name = "windows-link" 1411 | version = "0.2.1" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 1414 | 1415 | [[package]] 1416 | name = "windows-sys" 1417 | version = "0.52.0" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1420 | dependencies = [ 1421 | "windows-targets", 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "windows-sys" 1426 | version = "0.59.0" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1429 | dependencies = [ 1430 | "windows-targets", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "windows-sys" 1435 | version = "0.61.2" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 1438 | dependencies = [ 1439 | "windows-link", 1440 | ] 1441 | 1442 | [[package]] 1443 | name = "windows-targets" 1444 | version = "0.52.6" 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" 1446 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1447 | dependencies = [ 1448 | "windows_aarch64_gnullvm", 1449 | "windows_aarch64_msvc", 1450 | "windows_i686_gnu", 1451 | "windows_i686_gnullvm", 1452 | "windows_i686_msvc", 1453 | "windows_x86_64_gnu", 1454 | "windows_x86_64_gnullvm", 1455 | "windows_x86_64_msvc", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "windows_aarch64_gnullvm" 1460 | version = "0.52.6" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1463 | 1464 | [[package]] 1465 | name = "windows_aarch64_msvc" 1466 | version = "0.52.6" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1469 | 1470 | [[package]] 1471 | name = "windows_i686_gnu" 1472 | version = "0.52.6" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1475 | 1476 | [[package]] 1477 | name = "windows_i686_gnullvm" 1478 | version = "0.52.6" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1481 | 1482 | [[package]] 1483 | name = "windows_i686_msvc" 1484 | version = "0.52.6" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1487 | 1488 | [[package]] 1489 | name = "windows_x86_64_gnu" 1490 | version = "0.52.6" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1493 | 1494 | [[package]] 1495 | name = "windows_x86_64_gnullvm" 1496 | version = "0.52.6" 1497 | source = "registry+https://github.com/rust-lang/crates.io-index" 1498 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1499 | 1500 | [[package]] 1501 | name = "windows_x86_64_msvc" 1502 | version = "0.52.6" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1505 | 1506 | [[package]] 1507 | name = "wit-bindgen" 1508 | version = "0.46.0" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 1511 | 1512 | [[package]] 1513 | name = "writeable" 1514 | version = "0.6.1" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 1517 | 1518 | [[package]] 1519 | name = "yoke" 1520 | version = "0.8.0" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 1523 | dependencies = [ 1524 | "serde", 1525 | "stable_deref_trait", 1526 | "yoke-derive", 1527 | "zerofrom", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "yoke-derive" 1532 | version = "0.8.0" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 1535 | dependencies = [ 1536 | "proc-macro2", 1537 | "quote", 1538 | "syn 2.0.106", 1539 | "synstructure", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "zerocopy" 1544 | version = "0.8.27" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" 1547 | dependencies = [ 1548 | "zerocopy-derive", 1549 | ] 1550 | 1551 | [[package]] 1552 | name = "zerocopy-derive" 1553 | version = "0.8.27" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" 1556 | dependencies = [ 1557 | "proc-macro2", 1558 | "quote", 1559 | "syn 2.0.106", 1560 | ] 1561 | 1562 | [[package]] 1563 | name = "zerofrom" 1564 | version = "0.1.6" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 1567 | dependencies = [ 1568 | "zerofrom-derive", 1569 | ] 1570 | 1571 | [[package]] 1572 | name = "zerofrom-derive" 1573 | version = "0.1.6" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 1576 | dependencies = [ 1577 | "proc-macro2", 1578 | "quote", 1579 | "syn 2.0.106", 1580 | "synstructure", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "zerotrie" 1585 | version = "0.2.2" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 1588 | dependencies = [ 1589 | "displaydoc", 1590 | "yoke", 1591 | "zerofrom", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "zerovec" 1596 | version = "0.11.4" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" 1599 | dependencies = [ 1600 | "yoke", 1601 | "zerofrom", 1602 | "zerovec-derive", 1603 | ] 1604 | 1605 | [[package]] 1606 | name = "zerovec-derive" 1607 | version = "0.11.1" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 1610 | dependencies = [ 1611 | "proc-macro2", 1612 | "quote", 1613 | "syn 2.0.106", 1614 | ] 1615 | --------------------------------------------------------------------------------