mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-09-13 21:17:41 +02:00
Some more restructuring of the basic API. Closing #4 now, but surely this will still be refactored as more methods are added to the API.
This commit is contained in:
@@ -59,7 +59,9 @@ Currently we only provide an API for view the current state:
|
||||
| Resource | Method | Action |
|
||||
| ------------------------------ | -------- | ------------------------------- |
|
||||
| /publishers | Get | List all current publishers |
|
||||
| /publishers/{number}/response | Get | Get [repository response xml](https://tools.ietf.org/html/rfc8183#section-5.2.4)|
|
||||
| /publishers/{handle} | Get | Get publisher details |
|
||||
| /publishers/{handle}/id.cer | Get | Get publisher id certificate |
|
||||
| /publishers/{handle}/response-xml | Get | Get [repository response xml](https://tools.ietf.org/html/rfc8183#section-5.2.4)|
|
||||
|
||||
|
||||
For the moment publishers are configured by adding the publisher's ['publisher
|
||||
@@ -79,7 +81,9 @@ logic wrapping around the API to ensure that things are then synchronised.
|
||||
|
||||
## UI
|
||||
|
||||
To add static resources, add to the 'static' folder and include static mapping at the end of src/pubd/httpd.rs. You should be able to get to them if you restart the server.
|
||||
To add static resources, add to the 'static' folder and include static
|
||||
mapping at the end of src/pubd/httpd.rs. You should be able to get to them if
|
||||
you restart the server.
|
||||
|
||||
|
||||
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
//! Support for the Json API
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::ext_serde;
|
||||
use crate::provisioning::publisher::Publisher;
|
||||
use crate::rpki::uri;
|
||||
|
||||
//------------ Link ----------------------------------------------------------
|
||||
|
||||
/// Defines a link element to include as part of a links array in a Json
|
||||
/// response.
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct Link<'a> {
|
||||
rel: &'a str,
|
||||
link: String
|
||||
}
|
||||
|
||||
|
||||
//------------ PublisherSummaryInfo ------------------------------------------
|
||||
|
||||
/// Defines a summary of publisher information to be used in the publisher
|
||||
/// list.
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct PublisherSummaryInfo<'a> {
|
||||
id: &'a str,
|
||||
links: Vec<Link<'a>>
|
||||
}
|
||||
|
||||
impl<'a> PublisherSummaryInfo<'a> {
|
||||
pub fn from(
|
||||
publisher: &'a Publisher,
|
||||
path_publishers: &'a str
|
||||
) -> PublisherSummaryInfo<'a> {
|
||||
let id = publisher.name().as_str();
|
||||
let mut links = Vec::new();
|
||||
|
||||
let response_link = Link {
|
||||
rel: "response-xml",
|
||||
link: format!("{}/{}/response-xml", path_publishers, id)
|
||||
};
|
||||
let self_link = Link {
|
||||
rel: "self",
|
||||
link: format!("{}/{}", path_publishers, id)
|
||||
};
|
||||
|
||||
links.push(response_link);
|
||||
links.push(self_link);
|
||||
|
||||
PublisherSummaryInfo {
|
||||
id,
|
||||
links
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ PublisherList -------------------------------------------------
|
||||
|
||||
/// This type represents a list of (all) current publishers to show in the API
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct PublisherList<'a> {
|
||||
publishers: Vec<PublisherSummaryInfo<'a>>
|
||||
}
|
||||
|
||||
impl<'a> PublisherList<'a> {
|
||||
pub fn from(
|
||||
publishers: &'a Vec<Arc<Publisher>>,
|
||||
path_publishers: &'a str
|
||||
) -> PublisherList<'a> {
|
||||
let publishers: Vec<PublisherSummaryInfo> = publishers.iter().map(|p|
|
||||
PublisherSummaryInfo::from(&p, path_publishers)
|
||||
).collect();
|
||||
|
||||
PublisherList {
|
||||
publishers
|
||||
}
|
||||
}
|
||||
|
||||
pub fn publishers(&self) -> &Vec<PublisherSummaryInfo> {
|
||||
&self.publishers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ PublisherDetails ----------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct PublisherDetails<'a> {
|
||||
name: &'a str,
|
||||
#[serde(serialize_with = "ext_serde::ser_rsync_uri")]
|
||||
base_uri: &'a uri::Rsync,
|
||||
#[serde(serialize_with = "ext_serde::ser_http_uri")]
|
||||
service_uri: &'a uri::Http,
|
||||
links: Vec<Link<'a>>
|
||||
}
|
||||
|
||||
impl<'a> PublisherDetails<'a> {
|
||||
pub fn from(
|
||||
publisher: &'a Arc<Publisher>,
|
||||
path_publishers: &'a str
|
||||
) -> PublisherDetails<'a> {
|
||||
let name = publisher.name().as_str();
|
||||
let base_uri = publisher.base_uri();
|
||||
let service_uri = publisher.service_uri();
|
||||
|
||||
let mut links = Vec::new();
|
||||
links.push(Link {
|
||||
rel: "response-xml",
|
||||
link: format!("{}/{}/response-xml", path_publishers, name)
|
||||
});
|
||||
links.push(Link {
|
||||
rel: "id-cert",
|
||||
link: format!("{}/{}/id.cer", path_publishers, name)
|
||||
});
|
||||
|
||||
PublisherDetails {
|
||||
name,
|
||||
base_uri,
|
||||
service_uri,
|
||||
links
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ extern crate xml as xmlrs;
|
||||
extern crate ring;
|
||||
extern crate untrusted;
|
||||
|
||||
pub mod api;
|
||||
pub mod file;
|
||||
pub mod provisioning;
|
||||
pub mod pubc;
|
||||
|
||||
+62
-4
@@ -18,9 +18,13 @@ use crate::pubd::https;
|
||||
use crate::pubd::pubserver;
|
||||
use crate::pubd::pubserver::PubServer;
|
||||
use crate::remote::sigmsg::SignedMessage;
|
||||
use api::PublisherList;
|
||||
use api::PublisherDetails;
|
||||
|
||||
const NOT_FOUND: &'static [u8] = include_bytes!("../../static/html/404.html");
|
||||
|
||||
const PATH_PUBLISHERS: &'static str = "/api/v1/publishers";
|
||||
|
||||
//------------ PubServerApp --------------------------------------------------
|
||||
|
||||
pub struct PubServerApp(App<Arc<RwLock<PubServer>>>);
|
||||
@@ -31,9 +35,15 @@ impl PubServerApp {
|
||||
pub fn new(server: Arc<RwLock<PubServer>>) -> Self {
|
||||
let app = App::with_state(server)
|
||||
.middleware(middleware::Logger::default())
|
||||
.resource("/api/v1/publishers", |r| {
|
||||
.resource(PATH_PUBLISHERS, |r| {
|
||||
r.f(Self::publishers)
|
||||
})
|
||||
.resource("/api/v1/publishers/{handle}", |r| {
|
||||
r.f(Self::publisher_details)
|
||||
})
|
||||
.resource("/api/v1/publishers/{handle}/id.cer", |r| {
|
||||
r.f(Self::id_cert)
|
||||
})
|
||||
.resource("/api/v1/publishers/{handle}/response-xml", |r| {
|
||||
r.f(Self::repository_response)
|
||||
})
|
||||
@@ -156,7 +166,51 @@ impl PubServerApp {
|
||||
let server: RwLockReadGuard<PubServer> = req.state().read().unwrap();
|
||||
match server.publishers() {
|
||||
Err(e) => Self::server_error(Error::ServerError(e)),
|
||||
Ok(publishers) => Self::render_json(publishers)
|
||||
Ok(publishers) => {
|
||||
Self::render_json(
|
||||
PublisherList::from(&publishers, PATH_PUBLISHERS)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a json structure with publisher details
|
||||
fn publisher_details(req: &HttpRequest) -> HttpResponse {
|
||||
let server: RwLockReadGuard<PubServer> = req.state().read().unwrap();
|
||||
match req.match_info().get("handle") {
|
||||
None => Self::p404(req),
|
||||
Some(handle) => {
|
||||
match server.publisher(handle) {
|
||||
Ok(None) => Self::p404(req),
|
||||
Ok(Some(publisher)) => {
|
||||
Self::render_json(
|
||||
PublisherDetails::from(&publisher,
|
||||
PATH_PUBLISHERS)
|
||||
)
|
||||
},
|
||||
Err(e) => Self::server_error(Error::ServerError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the id.cer for a publisher
|
||||
fn id_cert(req: &HttpRequest) -> HttpResponse {
|
||||
let server: RwLockReadGuard<PubServer> = req.state().read().unwrap();
|
||||
match req.match_info().get("handle") {
|
||||
None => Self::p404(req),
|
||||
Some(handle) => {
|
||||
match server.publisher(handle) {
|
||||
Ok(None) => Self::p404(req),
|
||||
Ok(Some(publisher)) => {
|
||||
let bytes = publisher.id_cert().to_bytes();
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/pkix-cert")
|
||||
.body(bytes)
|
||||
},
|
||||
Err(e) => Self::server_error(Error::ServerError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +223,9 @@ impl PubServerApp {
|
||||
Some(handle) => {
|
||||
match server.repository_response(handle) {
|
||||
Ok(res) => {
|
||||
HttpResponse::Ok().body(res.encode_vec())
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/xml")
|
||||
.body(res.encode_vec())
|
||||
},
|
||||
Err(pubserver::Error::PublisherStoreError
|
||||
(publisher_store::Error::UnknownPublisher(_))) => {
|
||||
@@ -262,7 +318,9 @@ impl PubServerApp {
|
||||
fn render_json<O: Serialize>(object: O) -> HttpResponse {
|
||||
match serde_json::to_string(&object){
|
||||
Ok(enc) => {
|
||||
HttpResponse::Ok().body(enc)
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(enc)
|
||||
},
|
||||
Err(e) => Self::server_error(Error::JsonError(e))
|
||||
}
|
||||
|
||||
@@ -108,6 +108,15 @@ impl PubServer {
|
||||
.map_err(|e| { Error::PublisherStoreError(e) })
|
||||
}
|
||||
|
||||
/// Returns an option for a publisher.
|
||||
pub fn publisher(
|
||||
&self,
|
||||
publisher_name: &str
|
||||
) -> Result<Option<Arc<Publisher>>, Error> {
|
||||
self.publisher_store.publisher(publisher_name)
|
||||
.map_err(|e| Error::PublisherStoreError(e))
|
||||
}
|
||||
|
||||
/// Returns a repository response for the given publisher.
|
||||
///
|
||||
/// Returns an error if the publisher is unknown.
|
||||
|
||||
@@ -19,7 +19,6 @@ use rpubd::remote::oob::exchange::PublisherRequest;
|
||||
use rpubd::remote::oob::exchange::RepositoryResponse;
|
||||
use rpubd::file;
|
||||
use rpubd::file::CurrentFile;
|
||||
use rpubd::provisioning::publisher::Publisher;
|
||||
use rpubd::pubc::client::PubClient;
|
||||
use rpubd::pubd::config::Config;
|
||||
use rpubd::pubd::http::PubServerApp;
|
||||
@@ -68,13 +67,11 @@ fn client_publish_at_server() {
|
||||
// XXX TODO: Find a better way to know the server is ready!
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
|
||||
// Should see one configured publisher
|
||||
let mut res = reqwest::get("http://localhost:3000/publishers").unwrap();
|
||||
let pl: Vec<Publisher> = serde_json::from_str(&res.text().unwrap()).unwrap();
|
||||
assert_eq!(1, pl.len());
|
||||
|
||||
// Should get repository response for alice
|
||||
let mut res = reqwest::get("http://localhost:3000/publishers/alice").unwrap();
|
||||
let mut res = reqwest::get
|
||||
("http://localhost:3000/api/v1/publishers/alice/response-xml")
|
||||
.unwrap();
|
||||
|
||||
let repo_res = RepositoryResponse::decode(
|
||||
res.text().unwrap().as_bytes()
|
||||
).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user