diff --git a/README.md b/README.md
index d0f04dd1..69797a42 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/src/api/mod.rs b/src/api/mod.rs
new file mode 100644
index 00000000..d9f45a94
--- /dev/null
+++ b/src/api/mod.rs
@@ -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>
+}
+
+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>
+}
+
+impl<'a> PublisherList<'a> {
+ pub fn from(
+ publishers: &'a Vec>,
+ path_publishers: &'a str
+ ) -> PublisherList<'a> {
+ let publishers: Vec = publishers.iter().map(|p|
+ PublisherSummaryInfo::from(&p, path_publishers)
+ ).collect();
+
+ PublisherList {
+ publishers
+ }
+ }
+
+ pub fn publishers(&self) -> &Vec {
+ &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>
+}
+
+impl<'a> PublisherDetails<'a> {
+ pub fn from(
+ publisher: &'a Arc,
+ 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
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index b11585b8..8cec1251 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
diff --git a/src/pubd/http.rs b/src/pubd/http.rs
index 6b7e5c81..f83a7836 100644
--- a/src/pubd/http.rs
+++ b/src/pubd/http.rs
@@ -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>>);
@@ -31,9 +35,15 @@ impl PubServerApp {
pub fn new(server: Arc>) -> 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 = 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 = 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 = 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(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))
}
diff --git a/src/pubd/pubserver.rs b/src/pubd/pubserver.rs
index 445807b6..be4ae523 100644
--- a/src/pubd/pubserver.rs
+++ b/src/pubd/pubserver.rs
@@ -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