middleware

This commit is contained in:
Aiden McClelland
2021-07-27 16:40:51 -06:00
committed by Aiden McClelland
parent b807323fa4
commit 01ed3318cb
8 changed files with 381 additions and 22 deletions

188
appmgr/Cargo.lock generated
View File

@@ -49,6 +49,15 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "ascii-canvas"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
dependencies = [
"term 0.7.0",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.51" version = "0.1.51"
@@ -116,6 +125,17 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "basic-cookies"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb53b6b315f924c7f113b162e53b3901c05fc9966baf84d201dfcc7432a4bb38"
dependencies = [
"lalrpop",
"lalrpop-util",
"regex",
]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.55.1" version = "0.55.1"
@@ -140,6 +160,21 @@ dependencies = [
"which", "which",
] ]
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
@@ -463,6 +498,12 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-mac" name = "crypto-mac"
version = "0.7.0" version = "0.7.0"
@@ -557,6 +598,12 @@ dependencies = [
"syn 0.15.44", "syn 0.15.44",
] ]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.8.1" version = "0.8.1"
@@ -661,6 +708,7 @@ dependencies = [
"async-trait", "async-trait",
"avahi-sys", "avahi-sys",
"base32", "base32",
"basic-cookies",
"bollard", "bollard",
"chrono", "chrono",
"clap", "clap",
@@ -676,7 +724,7 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"nix 0.20.0", "nix 0.22.0",
"openssl", "openssl",
"patch-db", "patch-db",
"pin-project", "pin-project",
@@ -720,6 +768,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
version = "0.3.6" version = "0.3.6"
@@ -775,6 +832,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -1266,6 +1329,38 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
[[package]]
name = "lalrpop"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15174f1c529af5bf1283c3bc0058266b483a67156f79589fab2a25e23cf8988"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"ena",
"itertools 0.10.1",
"lalrpop-util",
"petgraph",
"pico-args",
"regex",
"regex-syntax",
"string_cache",
"term 0.7.0",
"tiny-keccak",
"unicode-xid 0.2.2",
]
[[package]]
name = "lalrpop-util"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e58cce361efcc90ba8a0a5f982c741ff86b603495bb15a998412e957dcd278"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -1415,6 +1510,12 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.19.1" version = "0.19.1"
@@ -1439,6 +1540,19 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "nix"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
"memoffset",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "5.1.2" version = "5.1.2"
@@ -1638,6 +1752,31 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.8" version = "1.0.8"
@@ -1688,6 +1827,12 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]] [[package]]
name = "prettytable-rs" name = "prettytable-rs"
version = "0.8.0" version = "0.8.0"
@@ -1698,7 +1843,7 @@ dependencies = [
"csv", "csv",
"encode_unicode", "encode_unicode",
"lazy_static", "lazy_static",
"term", "term 0.5.2",
"unicode-width", "unicode-width",
] ]
@@ -2314,6 +2459,12 @@ dependencies = [
"thread-id", "thread-id",
] ]
[[package]]
name = "siphasher"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.4" version = "0.4.4"
@@ -2376,6 +2527,7 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"bytes 1.0.1", "bytes 1.0.1",
"chrono",
"crc", "crc",
"crossbeam-channel", "crossbeam-channel",
"crossbeam-queue", "crossbeam-queue",
@@ -2449,6 +2601,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
]
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.2" version = "0.1.2"
@@ -2559,6 +2723,17 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.2"
@@ -2619,6 +2794,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.3.1" version = "1.3.1"

View File

@@ -45,50 +45,58 @@ production = []
[dependencies] [dependencies]
anyhow = "1.0.40" anyhow = "1.0.40"
async-trait = "0.1.42" async-trait = "0.1.42"
avahi-sys = { git="https://github.com/Start9Labs/avahi-sys", version="0.10.0", branch="feature/dynamic-linking", features=["dynamic"], optional=true } avahi-sys = { git = "https://github.com/Start9Labs/avahi-sys", version = "0.10.0", branch = "feature/dynamic-linking", features = [
"dynamic",
], optional = true }
base32 = "0.4.0" base32 = "0.4.0"
basic-cookies = "0.1.4"
bollard = "0.11.0" bollard = "0.11.0"
chrono = { version="0.4.19", features=["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
clap = "2.33" clap = "2.33"
digest = "0.9.0" digest = "0.9.0"
ed25519-dalek = { version="1.0.1", features=["serde"] } ed25519-dalek = { version = "1.0.1", features = ["serde"] }
emver = { version="0.1.2", features=["serde"] } emver = { version = "0.1.2", features = ["serde"] }
futures = "0.3.8" futures = "0.3.8"
git-version = "0.3.4" git-version = "0.3.4"
http = "0.2.3" http = "0.2.3"
indexmap = { version="1.6.2", features=["serde"] } indexmap = { version = "1.6.2", features = ["serde"] }
itertools = "0.10.0" itertools = "0.10.0"
jsonpath_lib = "0.3.0" jsonpath_lib = "0.3.0"
lazy_static = "1.4" lazy_static = "1.4"
libc = "0.2.86" libc = "0.2.86"
log = "0.4.11" log = "0.4.11"
nix = "0.20.0" nix = "0.22.0"
openssl = { version="0.10.30", features=["vendored"] } openssl = { version = "0.10.30", features = ["vendored"] }
patch-db = { version="*", path="../../patch-db/patch-db" } patch-db = { version = "*", path = "../../patch-db/patch-db" }
pin-project = "1.0.6" pin-project = "1.0.6"
prettytable-rs = "0.8.0" prettytable-rs = "0.8.0"
rand = "0.7.3" rand = "0.7.3"
regex = "1.4.2" regex = "1.4.2"
reqwest = { version="0.11.2", features=["stream", "json"] } reqwest = { version = "0.11.2", features = ["stream", "json"] }
rpassword = "5.0.0" rpassword = "5.0.0"
rpc-toolkit = { version="*", path="../../rpc-toolkit/rpc-toolkit" } rpc-toolkit = { version = "*", path = "../../rpc-toolkit/rpc-toolkit" }
rust-argon2 = "0.8.3" rust-argon2 = "0.8.3"
scopeguard = "1.1" # because avahi-sys fucks your shit up scopeguard = "1.1" # because avahi-sys fucks your shit up
serde = { version="1.0.118", features=["derive", "rc"] } serde = { version = "1.0.118", features = ["derive", "rc"] }
serde_cbor = "0.11.1" serde_cbor = "0.11.1"
serde_json = "1.0.59" serde_json = "1.0.59"
serde_toml = { package="toml", version="0.5.8" } serde_toml = { package = "toml", version = "0.5.8" }
serde_yaml = "0.8.14" serde_yaml = "0.8.14"
sha2 = "0.9.3" sha2 = "0.9.3"
simple-logging = "2.0" simple-logging = "2.0"
sqlx = { version="0.5", features=["runtime-tokio-rustls", "sqlite", "offline"] } sqlx = { version = "0.5", features = [
"runtime-tokio-rustls",
"sqlite",
"offline",
"chrono",
] }
tar = "0.4.35" tar = "0.4.35"
thiserror = "1.0.24" thiserror = "1.0.24"
tokio = { version="1.8.1", features=["full"] } tokio = { version = "1.8.1", features = ["full"] }
tokio-compat-02 = "0.2.0" tokio-compat-02 = "0.2.0"
tokio-stream = { version="0.1.5", features=["io-util", "sync"] } tokio-stream = { version = "0.1.5", features = ["io-util", "sync"] }
tokio-tar = "0.3.0" tokio-tar = "0.3.0"
tokio-util = { version="0.6.6", features=["io"] } tokio-util = { version = "0.6.6", features = ["io"] }
torut = "0.1.9" torut = "0.1.9"
typed-builder = "0.9.0" typed-builder = "0.9.0"
url = { version="2.2.1", features=["serde"] } url = { version = "2.2.1", features = ["serde"] }

View File

@@ -2,7 +2,14 @@
CREATE TABLE IF NOT EXISTS tor CREATE TABLE IF NOT EXISTS tor
( (
package TEXT NOT NULL, package TEXT NOT NULL,
interface TEXT NOT NULL, interface TEXT NOT NULL,
key BLOB NOT NULL, key BLOB NOT NULL,
PRIMARY KEY (package, interface) PRIMARY KEY (package, interface)
);
CREATE TABLE IF NOT EXISTS session
(
id TEXT NOT NULL PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
metadata JSON
); );

View File

@@ -3,6 +3,7 @@ use std::time::Duration;
use embassy::context::{EitherContext, RpcContext}; use embassy::context::{EitherContext, RpcContext};
use embassy::db::model::Database; use embassy::db::model::Database;
use embassy::middleware::cors::cors;
use embassy::status::{check_all, synchronize_all}; use embassy::status::{check_all, synchronize_all};
use embassy::util::daemon; use embassy::util::daemon;
use embassy::{Error, ErrorKind}; use embassy::{Error, ErrorKind};
@@ -28,6 +29,9 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> {
command: embassy::main_api, command: embassy::main_api,
context: ctx, context: ctx,
status: status_fn, status: status_fn,
middleware: [
cors
]
}); });
let status_ctx = rpc_ctx.clone(); let status_ctx = rpc_ctx.clone();
let status_daemon = daemon( let status_daemon = daemon(

View File

@@ -29,6 +29,7 @@ pub mod id;
pub mod inspect; pub mod inspect;
pub mod install; pub mod install;
pub mod manager; pub mod manager;
pub mod middleware;
pub mod migration; pub mod migration;
pub mod net; pub mod net;
pub mod registry; pub mod registry;
@@ -45,7 +46,7 @@ use rpc_toolkit::command;
use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::yajrc::RpcError;
pub use version::{init, self_update}; pub use version::{init, self_update};
#[command] #[command(metadata(authenticated = false))]
pub fn echo(#[context] _ctx: EitherContext, #[arg] message: String) -> Result<String, RpcError> { pub fn echo(#[context] _ctx: EitherContext, #[arg] message: String) -> Result<String, RpcError> {
Ok(message) Ok(message)
} }

View File

@@ -0,0 +1,105 @@
use anyhow::anyhow;
use basic_cookies::Cookie;
use chrono::Utc;
use futures::future::BoxFuture;
use futures::FutureExt;
use rpc_toolkit::hyper::header::COOKIE;
use rpc_toolkit::hyper::http::Error as HttpError;
use rpc_toolkit::hyper::{Body, Request, Response, StatusCode};
use rpc_toolkit::rpc_server_helpers::{
noop2, noop3, DynMiddleware, DynMiddlewareStage2, DynMiddlewareStage3,
};
use rpc_toolkit::yajrc::RpcMethod;
use rpc_toolkit::Metadata;
use serde::Deserialize;
use crate::context::RpcContext;
use crate::{Error, ResultExt};
async fn is_authed(ctx: &RpcContext, req: &Request<Body>) -> Result<bool, Error> {
if let Some(cookie_header) = req.headers().get(COOKIE) {
let cookies = Cookie::parse(
cookie_header
.to_str()
.with_kind(crate::ErrorKind::Authorization)?,
)
.with_kind(crate::ErrorKind::Authorization)?;
if let Some(session) = cookies.iter().find(|c| c.get_name() == "session") {
let id = session.get_value();
let exp = sqlx::query!("SELECT expires_at FROM session WHERE id = ?", id)
.fetch_one(&mut ctx.secret_store.acquire().await?)
.await?;
if exp.expires_at < Utc::now().naive_utc() {
return Ok(true);
}
}
}
Ok(false)
}
pub async fn auth<Params: for<'de> Deserialize<'de> + 'static, M: Metadata>(
ctx: RpcContext,
) -> DynMiddleware<Params, M> {
Box::new(
|req: &mut Request<Body>,
metadata: M|
-> BoxFuture<
Result<Result<DynMiddlewareStage2<Params>, Response<Body>>, HttpError>,
> {
async move {
match is_authed(&ctx, req).await {
Ok(true) => Ok(Ok(noop2())),
Ok(false) => Ok(Ok({
let mut fake_req = Request::new(Body::empty());
*fake_req.headers_mut() = req.headers().clone();
let m2: DynMiddlewareStage2<Params> =
Box::new(move |rpc_req| {
let method = rpc_req.method.as_str();
let res: Result<
Result<DynMiddlewareStage3, Response<Body>>,
HttpError,
> = if metadata.get(method, "login").unwrap_or(false) {
todo!("set cookie on success")
} else if !metadata.get(method, "authenticated").unwrap_or(true) {
Ok(Ok(noop3()))
} else {
rpc_toolkit::rpc_server_helpers::to_response(
&fake_req,
Ok((
rpc_req.id.clone(),
Err(Error::new(
anyhow!("UNAUTHORIZED"),
crate::ErrorKind::Authorization,
)
.into()),
)),
|_| StatusCode::OK,
)
.map(|a| Err(a))
};
async { res }.boxed()
});
m2
})),
Err(e) => Ok(Ok({
let mut fake_req = Request::new(Body::empty());
*fake_req.headers_mut() = req.headers().clone();
let m2: DynMiddlewareStage2<Params> = Box::new(move |rpc_req| {
let res: Result<
Result<DynMiddlewareStage3, Response<Body>>,
HttpError,
> = rpc_toolkit::rpc_server_helpers::to_response(
&fake_req,
Ok((rpc_req.id.clone(), Err(e.into()))),
|_| StatusCode::OK,
)
.map(|a| Err(a));
async { res }.boxed()
});
m2
})),
}
}
.boxed()
},
)
}

View File

@@ -0,0 +1,48 @@
use futures::FutureExt;
use rpc_toolkit::hyper::http::Error as HttpError;
use rpc_toolkit::hyper::{Body, Method, Request, Response};
use rpc_toolkit::rpc_server_helpers::{
DynMiddlewareStage2, DynMiddlewareStage3, DynMiddlewareStage4,
};
use serde::Deserialize;
pub async fn cors<Params: for<'de> Deserialize<'de> + 'static, Metadata>(
req: &mut Request<Body>,
) -> Result<Result<DynMiddlewareStage2<Params>, Response<Body>>, HttpError> {
if req.method() == Method::OPTIONS {
Ok(Err(Response::builder()
.header(
"Access-Control-Allow-Origin",
if let Some(origin) = req.headers().get("origin").and_then(|s| s.to_str().ok()) {
origin
} else {
"*"
},
)
.header("Access-Control-Allow-Methods", "*")
.header("Access-Control-Allow-Headers", "*")
.header("Access-Control-Allow-Credentials", "true")
.body(Body::empty())?))
} else {
Ok(Ok(Box::new(|_| {
async move {
let res: DynMiddlewareStage3 = Box::new(|_| {
async move {
let res: DynMiddlewareStage4 = Box::new(|res| {
async move {
res.headers_mut()
.insert("Access-Control-Allow-Origin", "*".parse()?);
Ok::<_, HttpError>(())
}
.boxed()
});
Ok::<_, HttpError>(Ok(res))
}
.boxed()
});
Ok::<_, HttpError>(Ok(res))
}
.boxed()
})))
}
}

View File

@@ -0,0 +1,2 @@
pub mod auth;
pub mod cors;