From d5026cb55e0826b9b94627b1de6426ecd317f6d5 Mon Sep 17 00:00:00 2001 From: Demetrius Kanios Date: Thu, 14 May 2026 09:19:37 -0700 Subject: [PATCH] feat(plugin-api): Integrate `wasmtime_wasi_http` (#2128) Co-authored-by: Alexander Medvedev --- Cargo.lock | 51 +++- Cargo.toml | 11 +- pumpkin-plugin-api/src/permissions.rs | 5 + pumpkin-protocol/fuzz/Cargo.lock | 289 ++++++++++++------ pumpkin/Cargo.toml | 3 +- .../src/plugin/loader/wasm/wasm_host/mod.rs | 7 +- .../src/plugin/loader/wasm/wasm_host/state.rs | 54 ++++ pumpkin/src/plugin/permissions.rs | 8 + 8 files changed, 327 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dace72112..8cc7bce88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1539,8 +1539,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "foldhash 0.2.0", - "serde", - "serde_core", ] [[package]] @@ -2838,6 +2836,7 @@ dependencies = [ "flate2", "futures", "hmac 0.13.0", + "hyper", "libloading", "notify", "num-bigint", @@ -2874,9 +2873,9 @@ dependencies = [ "tracing-subscriber", "ureq", "uuid", - "wasmparser 0.248.0", "wasmtime", "wasmtime-wasi", + "wasmtime-wasi-http", ] [[package]] @@ -3929,6 +3928,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.18" @@ -4244,7 +4253,7 @@ dependencies = [ "serde_json", "ureq-proto", "utf8-zero", - "webpki-roots", + "webpki-roots 1.0.7", ] [[package]] @@ -4527,10 +4536,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a" dependencies = [ "bitflags", - "hashbrown 0.17.1", "indexmap", "semver", - "serde", ] [[package]] @@ -4830,6 +4837,29 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "wasmtime-wasi-http" +version = "44.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff8f34bf2e8526278f0a0fe79e2b6387e1d932fda8783ab13a13bdc79b79159" +dependencies = [ + "async-trait", + "bytes", + "futures", + "http", + "http-body", + "http-body-util", + "hyper", + "rustls", + "tokio", + "tokio-rustls", + "tracing", + "wasmtime", + "wasmtime-wasi", + "wasmtime-wasi-io", + "webpki-roots 0.26.11", +] + [[package]] name = "wasmtime-wasi-io" version = "44.0.1" @@ -4865,6 +4895,15 @@ dependencies = [ "wast", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + [[package]] name = "webpki-roots" version = "1.0.7" diff --git a/Cargo.toml b/Cargo.toml index d01674336..d590f50b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,13 @@ inherits = "release" debug = true strip = false +[profile.dev] +debug = "line-tables-only" +debug-assertions = true +overflow-checks = false +split-debuginfo = "packed" +opt-level = 0 + [workspace.dependencies] tokio = { version = "1.52", default-features = false } syn = { version = "2.0", default-features = false, features = ["printing"] } @@ -180,8 +187,10 @@ notify = "8.2.0" wasmtime = "44.0" wasmtime-wasi = { version = "44.0", default-features = false, features = ["p2"] } +wasmtime-wasi-http = "44.0" +# needed for interacting with wasmtime-wasi-http - keep in sync +hyper = { version = "^1.7", features = ["full"] } wit-bindgen = "0.57" -wasmparser = "0.248" postcard = { version = "1.1", features = ["alloc"] } tracing-serde-structured = "0.4" diff --git a/pumpkin-plugin-api/src/permissions.rs b/pumpkin-plugin-api/src/permissions.rs index 5e2d1cdf6..e9b64ab4d 100644 --- a/pumpkin-plugin-api/src/permissions.rs +++ b/pumpkin-plugin-api/src/permissions.rs @@ -29,6 +29,11 @@ pub const NETWORK_LOOPBACK: &str = "network.loopback"; /// **Warning:** This is a powerful permission. pub const NETWORK_OUTBOUND: &str = "network.outbound"; +/// Allows the plugin to make outbound HTTP connections. +/// +/// This is separate from `network.outbound`. This allows the use of `wasi:http`; the other allows the more powerful `wasi:sockets`. +pub const HTTP_OUTBOUND: &str = "http.outbound"; + /// Allows the plugin to read files from the server's file system outside of its data folder. pub const FS_READ: &str = "fs.read"; diff --git a/pumpkin-protocol/fuzz/Cargo.lock b/pumpkin-protocol/fuzz/Cargo.lock index 6f2c82d0a..c6ef91b27 100644 --- a/pumpkin-protocol/fuzz/Cargo.lock +++ b/pumpkin-protocol/fuzz/Cargo.lock @@ -111,6 +111,12 @@ dependencies = [ "critical-section", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -684,9 +690,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "3.1.7" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0042e53977a94d5d10de04ce7eb6016aa212c08e83ea202f7a9f102ff104303" +checksum = "ebed7d0a3a92ebc771f880516a5eecef5942a0fc67855dc4f30e719b04c77ac5" dependencies = [ "crossbeam-utils", "futures-core", @@ -858,6 +864,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.1", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1249,6 +1265,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hash32" version = "0.2.1" @@ -1361,12 +1396,41 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hybrid-array" version = "0.4.10" @@ -1376,6 +1440,28 @@ dependencies = [ "typenum", ] +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -1653,12 +1739,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "leb128" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1958,6 +2038,15 @@ dependencies = [ "libc", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-core-foundation" version = "0.3.2" @@ -1965,6 +2054,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.11.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.1", + "objc2", ] [[package]] @@ -1977,6 +2084,17 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + [[package]] name = "object" version = "0.39.1" @@ -2297,6 +2415,7 @@ dependencies = [ "base64", "bitflags 2.11.1", "bytes", + "colored", "crossbeam", "dashmap", "flate2", @@ -2307,6 +2426,7 @@ dependencies = [ "num-bigint", "ordered-float", "postcard", + "pumpkin-codecs", "pumpkin-config", "pumpkin-data", "pumpkin-inventory", @@ -2336,9 +2456,10 @@ dependencies = [ "tracing-subscriber", "ureq", "uuid", - "wasmparser 0.247.0", + "wasmparser 0.248.0", "wasmtime", "wasmtime-wasi", + "wasmtime-wasi-http", ] [[package]] @@ -2382,6 +2503,7 @@ dependencies = [ "pumpkin-protocol", "pumpkin-util", "pumpkin-world", + "rand 0.10.1", "thiserror 2.0.18", "tokio", "tracing", @@ -2408,7 +2530,6 @@ dependencies = [ "serde", "thiserror 2.0.18", "tracing", - "uuid", ] [[package]] @@ -2477,6 +2598,7 @@ dependencies = [ name = "pumpkin-world" version = "0.1.0-dev+26.1" dependencies = [ + "arc-swap", "bitflags 2.11.1", "bytes", "crossbeam", @@ -2828,9 +2950,9 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" dependencies = [ "twox-hash 2.1.2", ] @@ -3148,15 +3270,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.38.4" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" +checksum = "a4deba334e1190ba7cb498327affa11e5ece10d26a30ab2f27fcf09504b8d8b6" dependencies = [ "libc", "memchr", "ntapi", "objc2-core-foundation", "objc2-io-kit", + "objc2-open-directory", "windows", ] @@ -3330,6 +3453,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -3482,6 +3615,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "twox-hash" version = "1.6.3" @@ -3551,7 +3690,7 @@ dependencies = [ "serde_json", "ureq-proto", "utf8-zero", - "webpki-roots", + "webpki-roots 1.0.7", ] [[package]] @@ -3631,6 +3770,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3786,9 +3934,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.247.0" +version = "0.248.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80" +checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a" dependencies = [ "bitflags 2.11.1", "hashbrown 0.17.0", @@ -3797,17 +3945,6 @@ dependencies = [ "serde", ] -[[package]] -name = "wasmparser" -version = "0.248.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a" -dependencies = [ - "bitflags 2.11.1", - "indexmap", - "semver", -] - [[package]] name = "wasmprinter" version = "0.246.2" @@ -4102,10 +4239,32 @@ dependencies = [ "url", "wasmtime", "wasmtime-wasi-io", - "wiggle", "windows-sys 0.61.2", ] +[[package]] +name = "wasmtime-wasi-http" +version = "44.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff8f34bf2e8526278f0a0fe79e2b6387e1d932fda8783ab13a13bdc79b79159" +dependencies = [ + "async-trait", + "bytes", + "futures", + "http", + "http-body", + "http-body-util", + "hyper", + "rustls", + "tokio", + "tokio-rustls", + "tracing", + "wasmtime", + "wasmtime-wasi", + "wasmtime-wasi-io", + "webpki-roots 0.26.11", +] + [[package]] name = "wasmtime-wasi-io" version = "44.0.1" @@ -4119,15 +4278,6 @@ dependencies = [ "wasmtime", ] -[[package]] -name = "wast" -version = "35.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" -dependencies = [ - "leb128", -] - [[package]] name = "wast" version = "248.0.0" @@ -4147,7 +4297,16 @@ version = "1.248.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75cd9e510603909748e6ebab89f27cd04472c1d9d85a3c88a7a6fc51a1a7934" dependencies = [ - "wast 248.0.0", + "wast", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", ] [[package]] @@ -4159,46 +4318,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "wiggle" -version = "44.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f878b066ad36054ad6e7724230f28ea7f981f44e595e39946d5225fd9e87755" -dependencies = [ - "bitflags 2.11.1", - "thiserror 2.0.18", - "tracing", - "wasmtime", - "wasmtime-environ", - "wiggle-macro", -] - -[[package]] -name = "wiggle-generate" -version = "44.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f57f0bc709dacc9c69869006457ab4e1bc9d93695400f06224f33cbe8af81778" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", - "wasmtime-environ", - "witx", -] - -[[package]] -name = "wiggle-macro" -version = "44.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63976fe41647f7c55c680b88a7b9b68aae9184f5a6b4a0971bf3eb39c287467f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wiggle-generate", -] - [[package]] name = "winapi" version = "0.3.9" @@ -4653,18 +4772,6 @@ dependencies = [ "wasmparser 0.246.2", ] -[[package]] -name = "witx" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" -dependencies = [ - "anyhow", - "log", - "thiserror 1.0.69", - "wast 35.0.2", -] - [[package]] name = "writeable" version = "0.6.3" diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 3f1c48f75..5fdd67841 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -100,7 +100,8 @@ console-subscriber = { workspace = true, optional = true } wasmtime = { workspace = true } wasmtime-wasi = { workspace = true } -wasmparser = { workspace = true } +wasmtime-wasi-http = { workspace = true } +hyper = { workspace = true } ordered-float = "5.3.0" diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/mod.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/mod.rs index 88cc12280..7f3dc43dd 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/mod.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/mod.rs @@ -21,8 +21,6 @@ pub enum PluginInitError { LinkerSetupFailed(wasmtime::Error), #[error("plugin API version mismatch")] ApiVersionMismatch, - #[error("failed to read payload for plugin")] - FailedToReadPayload(#[from] wasmparser::BinaryReaderError), #[error("failed to read plugin bytes")] FailedToReadPluginBytes(#[from] std::io::Error), #[error("plugin failed to load with error: {0}")] @@ -94,6 +92,7 @@ impl PluginRuntime { fn setup_linker(engine: &Engine) -> wasmtime::Result> { let mut linker = Linker::::new(engine); wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; + wasmtime_wasi_http::p2::add_only_http_to_linker_async(&mut linker)?; wit::v0_1::add_to_linker(&mut linker)?; Ok(linker) } @@ -257,6 +256,10 @@ impl WasmPlugin { file_perms, )?; + if has_permission(permissions::HTTP_OUTBOUND) { + store.data_mut().wasi_http_hooks.allow_outbound = true; + } + store.data_mut().permissions = filtered_permissions; store.data_mut().wasi_ctx = builder.build(); diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs index 7956264be..2b3ae8034 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs @@ -7,6 +7,13 @@ use pumpkin_util::text::TextComponent; use tokio::sync::Mutex; use wasmtime::component::ResourceTable; use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView}; +use wasmtime_wasi_http::{ + WasiHttpCtx, + p2::{ + HttpError, HttpResult, WasiHttpCtxView, WasiHttpHooks, WasiHttpView, + bindings::http::types::ErrorCode, default_send_request, + }, +}; use crate::{ command::{ @@ -49,6 +56,8 @@ pub type OwnedConsumedArgs = HashMap; pub struct PluginHostState { pub wasi_ctx: WasiCtx, + pub wasi_http_ctx: WasiHttpCtx, + pub wasi_http_hooks: PluginHttpHooks, pub resource_table: ResourceTable, pub plugin: Option>, pub server: Option>, @@ -67,6 +76,8 @@ impl PluginHostState { let resource_table = ResourceTable::new(); Self { wasi_ctx: WasiCtxBuilder::new().build(), + wasi_http_ctx: WasiHttpCtx::new(), + wasi_http_hooks: PluginHttpHooks::new(), resource_table, plugin: None, server: None, @@ -191,6 +202,39 @@ impl PluginHostState { } } +pub struct PluginHttpHooks { + pub allow_outbound: bool, +} + +impl PluginHttpHooks { + #[must_use] + pub const fn new() -> Self { + Self { + allow_outbound: false, + } + } +} + +impl Default for PluginHttpHooks { + fn default() -> Self { + Self::new() + } +} + +impl WasiHttpHooks for PluginHttpHooks { + fn send_request( + &mut self, + request: hyper::Request, + config: wasmtime_wasi_http::p2::types::OutgoingRequestConfig, + ) -> HttpResult { + if !self.allow_outbound { + return Err(HttpError::from(ErrorCode::HttpRequestDenied)); + } + + Ok(default_send_request(request, config)) + } +} + impl WasiView for PluginHostState { fn ctx(&mut self) -> WasiCtxView<'_> { WasiCtxView { @@ -199,3 +243,13 @@ impl WasiView for PluginHostState { } } } + +impl WasiHttpView for PluginHostState { + fn http(&mut self) -> WasiHttpCtxView<'_> { + WasiHttpCtxView { + ctx: &mut self.wasi_http_ctx, + table: &mut self.resource_table, + hooks: &mut self.wasi_http_hooks, + } + } +} diff --git a/pumpkin/src/plugin/permissions.rs b/pumpkin/src/plugin/permissions.rs index e9d632c10..1b6b906d0 100644 --- a/pumpkin/src/plugin/permissions.rs +++ b/pumpkin/src/plugin/permissions.rs @@ -33,6 +33,11 @@ pub const NETWORK_LOOPBACK: &str = "network.loopback"; /// **Warning:** This is a powerful permission and should only be granted to trusted plugins. pub const NETWORK_OUTBOUND: &str = "network.outbound"; +/// Allows the plugin to make outbound HTTP connections. +/// +/// This is separate from `network.outbound`. This allows the use of `wasi:http`; the other allows the more powerful `wasi:sockets`. +pub const HTTP_OUTBOUND: &str = "http.outbound"; + /// Allows the plugin to read files from the server's file system outside of its data folder. pub const FS_READ: &str = "fs.read"; @@ -90,6 +95,9 @@ pub fn get_permission_description(permission: &str) -> Option<&'static str> { NETWORK_OUTBOUND => { Some("Allows the plugin to make outbound TCP/UDP connections. (POWERFUL)") } + HTTP_OUTBOUND => { + Some("Allows the plugin to make outbound HTTP requests (through `wasi:http`)") + } FS_READ => Some( "Allows the plugin to read files from the server's file system outside of its data folder.", ),