aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--planetwars-server/Cargo.toml1
-rw-r--r--planetwars-server/src/modules/registry.rs57
2 files changed, 43 insertions, 15 deletions
diff --git a/planetwars-server/Cargo.toml b/planetwars-server/Cargo.toml
index 3e1f05e..d85a011 100644
--- a/planetwars-server/Cargo.toml
+++ b/planetwars-server/Cargo.toml
@@ -28,6 +28,7 @@ planetwars-matchrunner = { path = "../planetwars-matchrunner" }
config = { version = "0.12", features = ["toml"] }
thiserror = "1.0.31"
sha2 = "0.10"
+tokio-util = { version="0.7.3", features=["io"] }
# TODO: remove me
shlex = "1.1"
diff --git a/planetwars-server/src/modules/registry.rs b/planetwars-server/src/modules/registry.rs
index 6095527..9d71dd7 100644
--- a/planetwars-server/src/modules/registry.rs
+++ b/planetwars-server/src/modules/registry.rs
@@ -1,9 +1,11 @@
-use axum::body::{Body, StreamBody};
-use axum::extract::{BodyStream, Path, Query};
+use axum::body::{Body, Bytes, StreamBody};
+use axum::extract::{BodyStream, FromRequest, Path, Query, RequestParts, TypedHeader};
use axum::handler::Handler;
+use axum::headers::authorization::Basic;
+use axum::headers::Authorization;
use axum::response::{IntoResponse, Response};
use axum::routing::{get, head, post, put};
-use axum::Router;
+use axum::{async_trait, Router};
use hyper::StatusCode;
use serde::Serialize;
use sha2::{Digest, Sha256};
@@ -16,7 +18,8 @@ use crate::util::gen_alphanumeric;
const REGISTRY_PATH: &'static str = "./data/registry";
pub fn registry_service() -> Router {
Router::new()
- .nest("/v2", registry_api_v2())
+ // The docker API requires this trailing slash
+ .nest("/v2/", registry_api_v2())
.fallback(fallback.into_service())
}
@@ -41,8 +44,41 @@ async fn fallback(request: axum::http::Request<Body>) -> impl IntoResponse {
StatusCode::NOT_FOUND
}
-// root should return 200 OK to confirm api compliance
-async fn root_handler() -> Response<Body> {
+type AuthorizationHeader = TypedHeader<Authorization<Basic>>;
+
+struct RegistryAuth;
+
+#[async_trait]
+impl<B> FromRequest<B> for RegistryAuth
+where
+ B: Send,
+{
+ type Rejection = Response<axum::body::Full<Bytes>>;
+
+ async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
+ let TypedHeader(Authorization(_basic)) =
+ AuthorizationHeader::from_request(req).await.map_err(|_| {
+ let err = RegistryErrors {
+ errors: vec![RegistryError {
+ code: "UNAUTHORIZED".to_string(),
+ message: "please log in".to_string(),
+ detail: serde_json::Value::Null,
+ }],
+ };
+ Response::builder()
+ .status(StatusCode::UNAUTHORIZED)
+ .header("Docker-Distribution-API-Version", "registry/2.0")
+ .header("WWW-Authenticate", "Basic")
+ .body(axum::body::Full::from(serde_json::to_vec(&err).unwrap()))
+ .unwrap()
+ })?;
+
+ Ok(RegistryAuth)
+ }
+}
+
+async fn root_handler(_auth: RegistryAuth) -> impl IntoResponse {
+ // root should return 200 OK to confirm api compliance
Response::builder()
.status(StatusCode::OK)
.header("Docker-Distribution-API-Version", "registry/2.0")
@@ -89,15 +125,6 @@ async fn get_blob(
}
async fn blob_upload(Path(repository_name): Path<String>) -> impl IntoResponse {
- // let value = json!({
- // "errors": [
- // {
- // "code": "UNSUPPORTED",
- // "message": "not implemented yet lol",
- // }
- // ]
- // });
-
let uuid = gen_alphanumeric(16);
tokio::fs::File::create(PathBuf::from(REGISTRY_PATH).join("uploads").join(&uuid))
.await