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"
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]]
name = "async-trait"
version = "0.1.51"
@@ -116,6 +125,17 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "bindgen"
version = "0.55.1"
@@ -140,6 +160,21 @@ dependencies = [
"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]]
name = "bitflags"
version = "1.2.1"
@@ -463,6 +498,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.7.0"
@@ -557,6 +598,12 @@ dependencies = [
"syn 0.15.44",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "digest"
version = "0.8.1"
@@ -661,6 +708,7 @@ dependencies = [
"async-trait",
"avahi-sys",
"base32",
"basic-cookies",
"bollard",
"chrono",
"clap",
@@ -676,7 +724,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
"nix 0.20.0",
"nix 0.22.0",
"openssl",
"patch-db",
"pin-project",
@@ -720,6 +768,15 @@ dependencies = [
"serde",
]
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
@@ -775,6 +832,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fnv"
version = "1.0.7"
@@ -1266,6 +1329,38 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "lazy_static"
version = "1.4.0"
@@ -1415,6 +1510,12 @@ dependencies = [
"tempfile",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.19.1"
@@ -1439,6 +1540,19 @@ dependencies = [
"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]]
name = "nom"
version = "5.1.2"
@@ -1638,6 +1752,31 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "pin-project"
version = "1.0.8"
@@ -1688,6 +1827,12 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "prettytable-rs"
version = "0.8.0"
@@ -1698,7 +1843,7 @@ dependencies = [
"csv",
"encode_unicode",
"lazy_static",
"term",
"term 0.5.2",
"unicode-width",
]
@@ -2314,6 +2459,12 @@ dependencies = [
"thread-id",
]
[[package]]
name = "siphasher"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
[[package]]
name = "slab"
version = "0.4.4"
@@ -2376,6 +2527,7 @@ dependencies = [
"bitflags",
"byteorder",
"bytes 1.0.1",
"chrono",
"crc",
"crossbeam-channel",
"crossbeam-queue",
@@ -2449,6 +2601,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "stringprep"
version = "0.1.2"
@@ -2559,6 +2723,17 @@ dependencies = [
"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]]
name = "termcolor"
version = "1.1.2"
@@ -2619,6 +2794,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.3.1"

View File

@@ -45,50 +45,58 @@ production = []
[dependencies]
anyhow = "1.0.40"
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"
basic-cookies = "0.1.4"
bollard = "0.11.0"
chrono = { version="0.4.19", features=["serde"] }
chrono = { version = "0.4.19", features = ["serde"] }
clap = "2.33"
digest = "0.9.0"
ed25519-dalek = { version="1.0.1", features=["serde"] }
emver = { version="0.1.2", features=["serde"] }
ed25519-dalek = { version = "1.0.1", features = ["serde"] }
emver = { version = "0.1.2", features = ["serde"] }
futures = "0.3.8"
git-version = "0.3.4"
http = "0.2.3"
indexmap = { version="1.6.2", features=["serde"] }
indexmap = { version = "1.6.2", features = ["serde"] }
itertools = "0.10.0"
jsonpath_lib = "0.3.0"
lazy_static = "1.4"
libc = "0.2.86"
log = "0.4.11"
nix = "0.20.0"
openssl = { version="0.10.30", features=["vendored"] }
patch-db = { version="*", path="../../patch-db/patch-db" }
nix = "0.22.0"
openssl = { version = "0.10.30", features = ["vendored"] }
patch-db = { version = "*", path = "../../patch-db/patch-db" }
pin-project = "1.0.6"
prettytable-rs = "0.8.0"
rand = "0.7.3"
regex = "1.4.2"
reqwest = { version="0.11.2", features=["stream", "json"] }
reqwest = { version = "0.11.2", features = ["stream", "json"] }
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"
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_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"
sha2 = "0.9.3"
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"
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-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-util = { version="0.6.6", features=["io"] }
tokio-util = { version = "0.6.6", features = ["io"] }
torut = "0.1.9"
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
(
package TEXT NOT NULL,
interface TEXT NOT NULL,
key BLOB NOT NULL,
interface TEXT NOT NULL,
key BLOB NOT NULL,
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::db::model::Database;
use embassy::middleware::cors::cors;
use embassy::status::{check_all, synchronize_all};
use embassy::util::daemon;
use embassy::{Error, ErrorKind};
@@ -28,6 +29,9 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> {
command: embassy::main_api,
context: ctx,
status: status_fn,
middleware: [
cors
]
});
let status_ctx = rpc_ctx.clone();
let status_daemon = daemon(

View File

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