Some more work done to separate the CMS/XML protocol and JSON. Still some more cleanup coming. (see issue #34)

This commit is contained in:
Tim Bruijnzeels
2019-01-23 16:48:14 +01:00
parent dea1958d78
commit c2ba03e679
17 changed files with 550 additions and 418 deletions
+1
View File
@@ -28,6 +28,7 @@ serde_json = "^1.0"
syslog = "^4.0"
toml = "^0.4"
tokio = "^0.1"
uuid = "0.7"
xml-rs = "0.8.0"
# XXX Temporarily
-3
View File
@@ -34,9 +34,6 @@
# in their certificates.
#rrdp_base_uri = "http://127.0.0.1:3000/rrdp/"
# Specify the base service URI where publishers can connect.
#service_uri = "http://127.0.0.1:3000/rfc8181/"
# Log level
#
# The maximum log level ("off", "error", "warn", "info", or "debug") for
+45 -18
View File
@@ -163,6 +163,23 @@ impl PublisherSummary {
}
}
//------------ Rfc8181Details ------------------------------------------------
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Rfc8181Details {
#[serde(
serialize_with = "ext_serde::ser_http_uri",
deserialize_with = "ext_serde::de_http_uri")]
service_uri: uri::Http,
#[serde(
serialize_with = "ext_serde::ser_id_cert",
deserialize_with = "ext_serde::de_id_cert")]
id_cert: IdCert
}
//------------ PublisherDetails ----------------------------------------------
/// This type defines the publisher details fro:
@@ -177,16 +194,7 @@ pub struct PublisherDetails {
)]
base_uri: uri::Rsync,
#[serde(
deserialize_with = "ext_serde::de_http_uri",
serialize_with = "ext_serde::ser_http_uri"
)]
service_uri: uri::Http,
#[serde(
deserialize_with = "ext_serde::de_id_cert",
serialize_with = "ext_serde::ser_id_cert"
)]
identity_certificate: IdCert,
rfc8181: Option<Rfc8181Details>,
links: Vec<Link>
}
@@ -195,8 +203,11 @@ impl PublisherDetails {
pub fn publisher_handle(&self) -> &str {
&self.publisher_handle
}
pub fn identity_cert(&self) -> &IdCert {
&self.identity_certificate
pub fn identity_cert(&self) -> Option<&IdCert> {
match self.rfc8181 {
None => None,
Some(ref details) => Some(&details.id_cert)
}
}
}
@@ -219,12 +230,28 @@ impl Report for PublisherDetails {
},
ReportFormat::Text => {
let res = format!(
"publisher_handle: {}\n\
base uri: {}\n\
service_uri: {}",
self.publisher_handle, self.base_uri, self.service_uri
);
let mut res = String::new();
res.push_str("handle: ");
res.push_str(self.publisher_handle.as_str());
res.push_str("\n");
res.push_str("base uri: ");
res.push_str(self.base_uri.to_string().as_str());
res.push_str("\n");
if let Some(ref rfc8181) = self.rfc8181 {
res.push_str("RFC8181 Details:\n");
res.push_str(" service uri: ");
res.push_str(rfc8181.service_uri.to_string().as_str());
res.push_str("\n");
res.push_str(" id cert (base64): ");
res.push_str(
base64::encode(
rfc8181.id_cert.to_bytes().as_ref()
).as_str());
res.push_str("\n");
}
Ok(res)
},
+12 -3
View File
@@ -113,9 +113,15 @@ impl KrillClient {
let uri = format!("api/v1/publishers/{}", handle);
let res = self.get(uri.as_str())?;
let details: PublisherDetails = serde_json::from_str(&res)?;
let bytes = details.identity_cert().to_bytes();
file::save(&bytes, &file)?;
Ok(ApiResponse::Empty)
match details.identity_cert() {
Some(cert) => {
let bytes = cert.to_bytes();
file::save(&bytes, &file)?;
Ok(ApiResponse::Empty)
},
None => Err(Error::NoIdCert)
}
}
}
}
@@ -271,6 +277,9 @@ pub enum Error {
#[display(fmt="Can't read file: {}", _0)]
IoError(io::Error),
#[display(fmt="There is no known IdCert for this publisher")]
NoIdCert
}
impl From<reqwest::Error> for Error {
@@ -1,4 +1,4 @@
//! Support for various admin API methods
//! Process requests received, delegate, and wrap up the responses.
use std::error;
use std::sync::{RwLockReadGuard, RwLockWriteGuard};
use actix_web::{HttpResponse, ResponseError};
@@ -8,7 +8,22 @@ use crate::daemon::api::responses::{PublisherDetails, PublisherList};
use crate::daemon::http::server::{HttpRequest, PublisherHandle};
use crate::daemon::publishers;
use crate::daemon::krillserver::{self, KrillServer};
use crate::remote::rfc8183::PublisherRequest;
use remote::sigmsg::SignedMessage;
use daemon::api::requests::PublishDelta;
use daemon::api::requests::PublisherRequestChoice;
//------------ Support Functions ---------------------------------------------
/// Returns a server in a read lock
pub fn ro_server(req: &HttpRequest) -> RwLockReadGuard<KrillServer> {
req.state().read().unwrap()
}
/// Returns a server in a write lock
pub fn rw_server(req: &HttpRequest) -> RwLockWriteGuard<KrillServer> {
req.state().write().unwrap()
}
/// Helper function to render json output.
fn render_json<O: Serialize>(object: O) -> HttpResponse {
@@ -29,26 +44,24 @@ fn server_error(error: Error) -> HttpResponse {
error.error_response()
}
/// Returns a server in a read lock
fn ro_server(req: &HttpRequest) -> RwLockReadGuard<KrillServer> {
req.state().read().unwrap()
}
/// Returns a server in a write lock
fn rw_server(req: &HttpRequest) -> RwLockWriteGuard<KrillServer> {
req.state().write().unwrap()
}
/// A clean 404 result for the API (no content, not for humans)
fn api_not_found() -> HttpResponse {
HttpResponse::build(StatusCode::NOT_FOUND).finish()
}
/// A clean 200 result for the API (no content, not for humans)
fn api_ok() -> HttpResponse {
pub fn api_ok() -> HttpResponse {
HttpResponse::Ok().finish()
}
/// Returns the server health. XXX TODO: do a real test!
pub fn health(_r: &HttpRequest) -> HttpResponse {
api_ok()
}
//------------ Admin: Publishers ---------------------------------------------
/// Returns a json structure with all publishers in it.
pub fn publishers(req: &HttpRequest) -> HttpResponse {
match ro_server(req).publishers() {
@@ -65,23 +78,23 @@ pub fn publishers(req: &HttpRequest) -> HttpResponse {
/// Request XML is posted.
pub fn add_publisher(
req: HttpRequest,
pr: PublisherRequest
prc: PublisherRequestChoice
) -> HttpResponse {
let mut server = rw_server(&req);
let handle = pr.handle().clone();
match server.add_publisher(pr, &handle) {
match server.add_publisher(prc, None) {
Ok(()) => api_ok(),
Err(e) => server_error(Error::ServerError(e))
}
}
/// Adds a an explicitly named publisher.
pub fn add_named_publisher(
req: HttpRequest,
pr: PublisherRequest,
prc: PublisherRequestChoice,
handle: PublisherHandle
) -> HttpResponse {
let mut server = rw_server(&req);
match server.add_publisher(pr, handle.as_ref()) {
match server.add_publisher(prc, Some(handle.as_ref())) {
Ok(()) => api_ok(),
Err(e) => server_error(Error::ServerError(e))
}
@@ -101,41 +114,26 @@ pub fn remove_publisher(
}
}
/// Returns a json structure with publisher details
pub fn publisher_details(
req: HttpRequest,
handle: PublisherHandle
) -> HttpResponse {
match ro_server(&req).publisher(handle) {
let server = ro_server(&req);
match server.publisher(handle) {
Ok(None) => api_not_found(),
Ok(Some(publisher)) => {
render_json(
PublisherDetails::from(&publisher, "/api/v1/publishers")
PublisherDetails::from(
&publisher,
"/api/v1/publishers",
server.service_base_uri())
)
},
Err(e) => server_error(Error::ServerError(e))
}
}
/// Returns the id.cer for a publisher
pub fn id_cert(
req: HttpRequest,
handle: PublisherHandle
) -> HttpResponse {
match ro_server(&req).publisher(handle) {
Ok(None) => api_not_found(),
Ok(Some(publisher)) => {
let bytes = publisher.id_cert().to_bytes();
HttpResponse::Ok()
.content_type("application/pkix-cert")
.body(bytes)
},
Err(e) => server_error(Error::ServerError(e))
}
}
/// Shows the server's RFC8183 section 5.2.4 Repository Response XML
/// file for a known publisher.
pub fn repository_response(
@@ -158,6 +156,55 @@ pub fn repository_response(
}
}
//------------ Publication ---------------------------------------------------
/// Processes an RFC8181 query and returns the appropriate response.
pub fn handle_rfc8181_request(
req: HttpRequest,
msg: SignedMessage,
handle: PublisherHandle
) -> HttpResponse {
let mut server: RwLockWriteGuard<KrillServer> = rw_server(&req);
match server.handle_rfc8181_request(&msg, handle.as_ref()) {
Ok(captured) => {
HttpResponse::build(StatusCode::OK)
.content_type("application/rpki-publication")
.body(captured.into_bytes())
}
Err(e) => {
server_error(Error::ServerError(e))
}
}
}
/// Processes a publishdelta request sent to the API.
pub fn handle_delta(
req: HttpRequest,
delta: PublishDelta,
handle: PublisherHandle
) -> HttpResponse {
match rw_server(&req).handle_delta(delta, handle.as_ref()) {
Ok(()) => api_ok(),
Err(e) => server_error(Error::ServerError(e))
}
}
/// Processes a list request sent to the API.
pub fn handle_list(
req: HttpRequest,
handle: PublisherHandle
) -> HttpResponse {
match ro_server(&req).handle_list(handle.as_ref()) {
Ok(list) => render_json(list),
Err(e) => server_error(Error::ServerError(e))
}
}
//------------ Error ---------------------------------------------------------
#[derive(Debug, Display)]
@@ -214,6 +261,7 @@ impl ErrorToStatus for krillserver::Error {
krillserver::Error::CmsProxy(_) => StatusCode::BAD_REQUEST,
krillserver::Error::PublisherStore(e) => e.status(),
krillserver::Error::Repository(_) => StatusCode::BAD_REQUEST,
krillserver::Error::NoIdCert => StatusCode::FORBIDDEN,
}
}
}
@@ -224,6 +272,8 @@ impl ErrorToCode for krillserver::Error {
krillserver::Error::PublisherStore(e) => e.code(),
krillserver::Error::Repository(_) => 3002,
krillserver::Error::CmsProxy(_) => 3003,
krillserver::Error::NoIdCert => 2001,
}
}
}
@@ -253,7 +303,6 @@ impl ErrorToStatus for publishers::Error {
}
}
#[derive(Debug, Serialize)]
struct ErrorResponse {
code: usize,
@@ -269,7 +318,6 @@ impl Error {
}
}
impl actix_web::ResponseError for Error {
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status())
+1 -1
View File
@@ -1,4 +1,4 @@
pub mod admin;
pub mod endpoints;
pub mod auth;
pub mod responses;
pub mod requests;
+31 -4
View File
@@ -1,18 +1,45 @@
//! Support for requests sent to the Json API
//!
//! So, contrary to the responses, we need to deal with actual values here
//! when we deserialize things being sent on the wire.
use bytes::Bytes;
use rpki::uri;
use uuid::Uuid;
use crate::remote::rfc8183;
use crate::util::ext_serde;
/// Auto-generate a token in case none is supplied.
pub fn generate_random_token() -> String {
Uuid::new_v4().to_string()
}
#[derive(Deserialize, Serialize)]
pub struct PublisherRequest {
handle: String,
#[serde(default = "generate_random_token")]
token: String,
}
impl PublisherRequest {
pub fn parts(self) -> (String, String) { (self.handle, self.token) }
}
/// This type provides a convenience wrapper so that either XML (rfc81838) or
/// Json (our CMS-less api) bodies may be sent when a publisher is added.
/// Dependent on the content the body sent this will be converted into the
/// right type.
pub enum PublisherRequestChoice {
Api(PublisherRequest),
Rfc8183(rfc8183::PublisherRequest)
}
/// This type provides a convenience wrapper to contain the request found
/// inside of a validated RFC8181 request.
pub enum PublishRequest {
List,
Delta(PublishDelta)
}
/// This type represents the request containing the complete delta of objects
/// to publish, update, or withdraw.
#[derive(Deserialize, Serialize)]
+31 -13
View File
@@ -5,9 +5,9 @@
use std::sync::Arc;
use rpki::uri;
use crate::daemon::publishers::Publisher;
use crate::remote::id::IdCert;
use crate::util::ext_serde;
use crate::util::file::CurrentFile;
use crate::remote::id::IdCert;
//------------ Link ----------------------------------------------------------
@@ -35,7 +35,7 @@ impl<'a> PublisherSummaryInfo<'a> {
publisher: &'a Publisher,
path_publishers: &'a str
) -> PublisherSummaryInfo<'a> {
let id = publisher.name().as_str();
let id = publisher.handle().as_str();
let mut links = Vec::new();
let response_link = Link {
@@ -88,6 +88,16 @@ impl<'a> PublisherList<'a> {
//------------ PublisherDetails ----------------------------------------------
#[derive(Clone, Debug, Serialize)]
pub struct Rfc8181Details<'a> {
#[serde(serialize_with = "ext_serde::ser_http_uri")]
service_uri: uri::Http,
#[serde(serialize_with = "ext_serde::ser_id_cert")]
id_cert: &'a IdCert
}
#[derive(Clone, Debug, Serialize)]
pub struct PublisherDetails<'a> {
publisher_handle: &'a str,
@@ -95,11 +105,7 @@ pub struct PublisherDetails<'a> {
#[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,
#[serde(serialize_with = "ext_serde::ser_id_cert")]
identity_certificate: &'a IdCert,
rfc8181: Option<Rfc8181Details<'a>>,
links: Vec<Link<'a>>
}
@@ -107,12 +113,25 @@ pub struct PublisherDetails<'a> {
impl<'a> PublisherDetails<'a> {
pub fn from(
publisher: &'a Arc<Publisher>,
path_publishers: &'a str
path_publishers: &'a str,
base_service_uri: &uri::Http
) -> PublisherDetails<'a> {
let handle = publisher.name().as_str();
let handle = publisher.handle().as_str();
let base_uri = publisher.base_uri();
let service_uri = publisher.service_uri();
let identity_certificate = publisher.id_cert();
// Derive the RFC8181 service URI.
let service_uri = format!("{}{}", base_service_uri, handle);
let service_uri = uri::Http::from_string(service_uri).unwrap();
let rfc8181 = match publisher.rfc8181() {
None => None,
Some(details) => Some(
Rfc8181Details {
service_uri,
id_cert: details.id_cert()
}
)
};
let mut links = Vec::new();
links.push(Link {
@@ -123,8 +142,7 @@ impl<'a> PublisherDetails<'a> {
PublisherDetails {
publisher_handle: handle,
base_uri,
service_uri,
identity_certificate,
rfc8181,
links
}
}
+14 -11
View File
@@ -30,9 +30,6 @@ impl ConfigDefaults {
fn rrdp_base_uri() -> uri::Http {
uri::Http::from_str("http://127.0.0.1:3000/rrdp/").unwrap()
}
fn service_uri() -> uri::Http {
uri::Http::from_str("http://127.0.0.1:3000/rfc8181/").unwrap()
}
fn log_level() -> LevelFilter { LevelFilter::Warn }
fn log_type() -> LogType { LogType::Syslog }
fn syslog_facility() -> Facility { Facility::LOG_DAEMON }
@@ -86,12 +83,6 @@ pub struct Config {
)]
pub rrdp_base_uri: uri::Http,
#[serde(
default = "ConfigDefaults::service_uri",
deserialize_with = "ext_serde::de_http_uri"
)]
pub service_uri: uri::Http,
#[serde(
default = "ConfigDefaults::log_level",
deserialize_with = "ext_serde::de_level_filter"
@@ -141,6 +132,20 @@ impl Config {
path.push(ssl::KEY_FILE);
path
}
pub fn service_uri(&self) -> uri::Http {
let mut uri = String::new();
if self.use_ssl() {
uri.push_str("https://");
} else {
uri.push_str("http://");
}
uri.push_str(&self.socket_addr().to_string());
uri.push_str("/");
uri::Http::from_string(uri).unwrap()
}
}
/// # Create
@@ -154,7 +159,6 @@ impl Config {
let data_dir = data_dir.clone();
let rsync_base = ConfigDefaults::rsync_base();
let rrdp_base_uri = ConfigDefaults::rrdp_base_uri();
let service_uri = ConfigDefaults::service_uri();
let log_level = ConfigDefaults::log_level();
let log_type = LogType::Stderr;
let log_file = ConfigDefaults::log_file();
@@ -168,7 +172,6 @@ impl Config {
data_dir,
rsync_base,
rrdp_base_uri,
service_uri,
log_level,
log_type,
log_file,
+66 -84
View File
@@ -1,23 +1,29 @@
//! Actix-web based HTTP server for the publication server.
//!
//! Here we deal with booting and setup, and once active deal with parsing
//! arguments and routing of requests, typically handing off to the
//! daemon::api::endpoints functions for processing and responding.
use std::error;
use std::fs::File;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use actix_web::{pred, fs, server};
use actix_web::{App, FromRequest, HttpResponse, ResponseError};
use actix_web::{App, FromRequest, HttpResponse};
use actix_web::dev::MessageBody;
use actix_web::middleware;
use actix_web::http::{Method, StatusCode };
use bcder::decode;
use futures::Future;
use openssl::ssl::{SslMethod, SslAcceptor, SslAcceptorBuilder, SslFiletype};
use crate::daemon::api::admin;
use crate::daemon::api::endpoints;
use crate::daemon::api::auth::{Authorizer, CheckAuthorisation};
use crate::daemon::api::requests::PublishDelta;
use crate::daemon::config::Config;
use crate::daemon::http::ssl;
use crate::daemon::krillserver;
use crate::daemon::krillserver::KrillServer;
use crate::remote::rfc8183::{PublisherRequest, PublisherRequestError};
use crate::remote::rfc8183;
use crate::remote::sigmsg::SignedMessage;
use daemon::api::requests::PublisherRequestChoice;
const NOT_FOUND: &'static [u8] = include_bytes!("../../../ui/dev/html/404.html");
@@ -25,6 +31,7 @@ const NOT_FOUND: &'static [u8] = include_bytes!("../../../ui/dev/html/404.html")
pub struct PubServerApp(App<Arc<RwLock<KrillServer>>>);
/// # Set up methods
///
impl PubServerApp {
@@ -33,32 +40,32 @@ impl PubServerApp {
.middleware(middleware::Logger::default())
.middleware(CheckAuthorisation)
.resource("/api/v1/publishers", |r| {
r.method(Method::GET).f(admin::publishers);
r.method(Method::POST).with(admin::add_publisher);
r.method(Method::GET).f(endpoints::publishers);
r.method(Method::POST).with(endpoints::add_publisher);
})
.resource("/api/v1/publishers/{handle}", |r| {
r.method(Method::GET).with(admin::publisher_details);
r.method(Method::POST).with(admin::add_named_publisher);
r.method(Method::DELETE).with(admin::remove_publisher);
r.method(Method::GET).with(endpoints::publisher_details);
r.method(Method::POST).with(endpoints::add_named_publisher);
r.method(Method::DELETE).with(endpoints::remove_publisher);
})
// For clients that cannot handle http methods
.resource("/api/v1/publishers/{handle}/del", |r| {
r.method(Method::POST).with(admin::remove_publisher);
r.method(Method::POST).with(endpoints::remove_publisher);
})
.resource("/api/v1/publishers/{handle}/response.xml", |r| {
r.method(Method::GET).with(admin::repository_response)
})
.resource("/api/v1/health", |r| {
r.method(Method::GET).f(Self::api_ok)
r.method(Method::GET).with(endpoints::repository_response)
})
.resource("/rfc8181/{handle}", |r| {
r.method(Method::POST).with(Self::process_publish_request)
r.method(Method::POST).with(endpoints::handle_rfc8181_request)
})
.resource("/rrdp/{path:.*}", |r| {
r.method(Method::GET).f(Self::serve_rrdp_files)
})
.resource("/health", |r| {
r.method(Method::GET).f(Self::service_ok)
.resource("/health", |r| { // No authentication required
r.method(Method::GET).f(endpoints::health)
})
.resource("/api/v1/health", |r| { // health with authentication
r.method(Method::GET).f(endpoints::health)
})
.default_resource(|r| {
// 404 for GET request
@@ -90,7 +97,7 @@ impl PubServerApp {
let pub_server = match KrillServer::new(
&config.data_dir,
&config.rsync_base,
&config.service_uri,
config.service_uri(),
&config.rrdp_base_uri,
authorizer
) {
@@ -103,7 +110,7 @@ impl PubServerApp {
Arc::new(RwLock::new(pub_server))
}
/// Used to start the server with an existing executor (e.g. in tests)
/// Used to start the server with an existing executor (for tests)
///
/// Note https is not supported in tests.
pub fn start(config: &Config) {
@@ -144,6 +151,8 @@ impl PubServerApp {
}
}
/// Used to set up HTTPS. Creates keypair and self signed certificate
/// if config has 'use_ssl=test'.
fn https_builder(config: &Config) -> Result<SslAcceptorBuilder, Error> {
if config.test_ssl() {
ssl::create_key_cert_if_needed(&config.data_dir)
@@ -180,45 +189,6 @@ impl PubServerApp {
}
}
/// Processes an RFC8181 query and returns the appropriate response.
///
/// Note this method checks whether the request can be decoded only, and
/// if successful delegates to [`handle_signed_request`] for further
/// processing.
///
/// [`handle_signed_request`]: #method.handle_signed_request
fn process_publish_request(
req: HttpRequest,
handle: PublisherHandle,
msg: SignedMessage
) -> HttpResponse {
debug!("Processing publish request");
Self::handle_signed_request(
req.state().write().unwrap(),
&msg,
handle.0.as_str()
)
}
/// Handles a decoded RFC8181 query.
///
/// This delegates to `PubServer` to do the actual hard work.
fn handle_signed_request(
mut server: RwLockWriteGuard<KrillServer>,
msg: &SignedMessage,
handle: &str
) -> HttpResponse {
match server.handle_request(msg, handle) {
Ok(captured) => {
HttpResponse::build(StatusCode::OK)
.content_type("application/rpki-publication")
.body(captured.into_bytes())
}
Err(e) => {
Self::server_error(Error::ServerError(e))
}
}
}
// XXX TODO: use a better handler that does not load everything into
// memory first, and set the correct headers for caching.
@@ -248,24 +218,6 @@ impl PubServerApp {
None => Self::p404(req)
}
}
/// API health check, expect that caller authenticates.
fn api_ok(_r: &HttpRequest) -> HttpResponse {
HttpResponse::Ok().body("")
}
/// Simple human server status response page.
fn service_ok(_r: &HttpRequest) -> HttpResponse {
// XXX TODO: do a real check
HttpResponse::Ok().body("I am completely operational, and all my circuits are functioning perfectly.")
}
/// Helper function to render server side errors. Also responsible for
/// logging the errors.
fn server_error(error: Error) -> HttpResponse {
error!("{}", error);
error.error_response()
}
}
@@ -313,10 +265,14 @@ impl Default for SignedMessageConvertConfig {
}
}
//------------ PublisherRequest ----------------------------------------------
/// Support converting requests into PublisherRequest
impl<S: 'static> FromRequest<S> for PublisherRequest {
//------------ PublisherRequestChoice ----------------------------------------
/// Converts the body sent to 'add publisher' end-points to a
/// PublisherRequestChoice, which contains either an
/// rfc8183::PublisherRequest, or an API publisher request (no ID certs and
/// CMS etc).
impl<S: 'static> FromRequest<S> for PublisherRequestChoice {
type Config = ();
type Result = Box<Future<Item=Self, Error=actix_web::Error>>;
@@ -327,12 +283,15 @@ impl<S: 'static> FromRequest<S> for PublisherRequest {
Box::new(MessageBody::new(req)
.from_err()
.and_then(|bytes| {
match PublisherRequest::decode(bytes.as_ref()) {
Ok(req) => Ok(req),
Err(e) => Err(Error::PublisherRequestError(e).into())
if bytes.starts_with(b"<") { // check content-type instead?
match rfc8183::PublisherRequest::decode(bytes.as_ref()) {
Ok(req) => Ok(PublisherRequestChoice::Rfc8183(req)),
Err(e) => Err(Error::Wrong8183Xml(e).into())
}
} else {
unimplemented!()
}
})
)
}
}
@@ -368,6 +327,29 @@ impl AsRef<str> for PublisherHandle {
}
//------------ PublishDelta --------------------------------------------------
/// Support converting request body into PublishDelta
impl<S: 'static> FromRequest<S> for PublishDelta {
type Config = ();
type Result = Box<Future<Item=Self, Error=actix_web::Error>>;
fn from_request(
req: &actix_web::HttpRequest<S>,
_cfg: &Self::Config
) -> Self::Result {
Box::new(MessageBody::new(req)
.from_err()
.and_then(|bytes| {
let delta: PublishDelta =
serde_json::from_reader(bytes.as_ref())
.map_err(|e| Error::JsonError(e))?;
Ok(delta)
})
)
}
}
//------------ IntoHttpHandler -----------------------------------------------
impl server::IntoHttpHandler for PubServerApp {
@@ -409,7 +391,7 @@ pub enum Error {
DecodeError(decode::Error),
#[display(fmt = "Cannot decode request: {}", _0)]
PublisherRequestError(PublisherRequestError),
Wrong8183Xml(rfc8183::PublisherRequestError),
#[display(fmt = "Wrong path")]
WrongPath,
+39 -17
View File
@@ -10,8 +10,9 @@ use crate::daemon::api::responses;
use crate::daemon::publishers::{self, Publisher, PublisherStore};
use crate::daemon::repo::{self, Repository, RRDP_FOLDER};
use crate::remote::cmsproxy::{self, CmsProxy};
use crate::remote::rfc8183::{PublisherRequest, RepositoryResponse};
use crate::remote::sigmsg::SignedMessage;
use daemon::api::requests::PublisherRequestChoice;
use remote::rfc8183;
/// # Naming things in the keystore.
const ACTOR: &'static str = "krill pubd";
@@ -33,6 +34,9 @@ const ACTOR: &'static str = "krill pubd";
/// * Updates the RRDP files
#[derive(Clone, Debug)]
pub struct KrillServer {
// The base URI for this service
service_uri: uri::Http,
// The base working directory, used for various storage
work_dir: PathBuf,
@@ -56,16 +60,17 @@ impl KrillServer {
pub fn new(
work_dir: &PathBuf,
base_uri: &uri::Rsync,
service_uri: &uri::Http,
service_uri: uri::Http,
rrdp_base_uri: &uri::Http,
authorizer: Authorizer
) -> Result<Self, Error> {
let cms_proxy = CmsProxy::new(work_dir, service_uri)?;
let cms_proxy = CmsProxy::new(work_dir)?;
let publisher_store = PublisherStore::new(work_dir, base_uri)?;
let repository = Repository::new(rrdp_base_uri, work_dir)?;
Ok(
KrillServer {
service_uri,
work_dir: work_dir.clone(),
authorizer,
cms_proxy,
@@ -74,6 +79,10 @@ impl KrillServer {
}
)
}
pub fn service_base_uri(&self) -> &uri::Http {
&self.service_uri
}
}
impl KrillServer {
@@ -94,13 +103,12 @@ impl KrillServer {
/// Adds the publishers, blows up if it already existed.
pub fn add_publisher(
&mut self,
req: PublisherRequest,
handle: &str,
prc: PublisherRequestChoice,
handle_override: Option<&str>,
) -> Result<(), Error> {
self.publisher_store.add_publisher(
req,
handle,
self.cms_proxy.base_service_uri(),
prc,
handle_override,
ACTOR
)?;
Ok(())
@@ -133,11 +141,14 @@ impl KrillServer {
pub fn repository_response(
&self,
name: impl AsRef<str>
) -> Result<RepositoryResponse, Error> {
) -> Result<rfc8183::RepositoryResponse, Error> {
let publisher = self.publisher_store.get_publisher(name)?;
let rrdp_notification = self.repository.rrdp_notification_uri();
self.cms_proxy
.repository_response(publisher, rrdp_notification)
.repository_response(
publisher,
self.service_base_uri(),
rrdp_notification)
.map_err(|e| Error::CmsProxy(e))
}
@@ -164,7 +175,7 @@ impl KrillServer {
/// Also note that if garbage is sent to the daemon, this garbage will
/// fail to parse as a SignedMessage, and the daemon will just respond
/// with an HTTP error response, without invoking any of this.
pub fn handle_request(
pub fn handle_rfc8181_request(
&mut self,
sigmsg: &SignedMessage,
handle: &str
@@ -172,15 +183,23 @@ impl KrillServer {
debug!("Handling request for: {}", handle);
let publisher = self.publisher_store.get_publisher(handle)?;
match self.cms_proxy.publish_request(sigmsg, publisher.id_cert()) {
let id_cert = match publisher.rfc8181() {
Some(details) => details.id_cert(),
None => return Err(Error::NoIdCert)
};
match self.cms_proxy.publish_request(sigmsg, id_cert) {
Err(e) => self.cms_proxy.wrap_error(e).map_err(|e| Error::CmsProxy(e)),
Ok(req) => {
let reply = match req {
PublishRequest::List => {
self.handle_list(handle)
self.handle_list(handle).map(|list|
responses::PublishReply::List(list))
},
PublishRequest::Delta(delta) => {
self.handle_delta(delta, handle)
self.handle_delta(delta, handle).map(|_|
responses::PublishReply::Success)
}
};
@@ -199,7 +218,7 @@ impl KrillServer {
&mut self,
delta: PublishDelta,
handle: &str
) -> Result<responses::PublishReply, Error> {
) -> Result<(), Error> {
let publisher = self.publisher_store.get_publisher(handle)?;
let base_uri = publisher.base_uri();
self.repository.publish(&delta, base_uri)
@@ -208,9 +227,9 @@ impl KrillServer {
/// Handles a list request sent to the API, or.. through the CmsProxy.
pub fn handle_list(
&mut self,
&self,
handle: &str
) -> Result<responses::PublishReply, Error> {
) -> Result<responses::ListReply, Error> {
let publisher = self.publisher_store.get_publisher(handle)?;
let base_uri = publisher.base_uri();
self.repository.list(base_uri).map_err(|e| Error::Repository(e))
@@ -231,6 +250,9 @@ pub enum Error {
#[display(fmt="{}", _0)]
Repository(repo::Error),
#[display(fmt="No IdCert known for this publisher")]
NoIdCert
}
impl From<cmsproxy::Error> for Error {
+177 -197
View File
@@ -5,91 +5,29 @@ use std::io;
use std::path::PathBuf;
use std::sync::Arc;
use rpki::uri;
use daemon::api::requests;
use daemon::api::requests::PublisherRequestChoice;
use crate::remote::id::IdCert;
use crate::remote::rfc8183::{PublisherRequest, PublisherRequestError};
use crate::remote::rfc8183;
use crate::storage::keystore::{self, Info, Key, KeyStore};
use crate::storage::caching_ks::CachingDiskKeyStore;
use crate::util::ext_serde;
//------------ Publisher -----------------------------------------------------
/// This type defines Publisher CAs that are allowed to publish.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Publisher {
pub struct Rfc8181PublisherDetails {
// The optional tag in the request. None maps to empty string.
tag: String,
name: String,
#[serde(
deserialize_with = "ext_serde::de_rsync_uri",
serialize_with = "ext_serde::ser_rsync_uri")]
base_uri: uri::Rsync,
#[serde(
deserialize_with = "ext_serde::de_http_uri",
serialize_with = "ext_serde::ser_http_uri")]
service_uri: uri::Http,
#[serde(
deserialize_with = "ext_serde::de_id_cert",
serialize_with = "ext_serde::ser_id_cert")]
id_cert: IdCert
}
impl Publisher {
pub fn new(
tag: Option<String>,
name: String,
base_uri: uri::Rsync,
service_uri: uri::Http,
id_cert: IdCert
) -> Self {
let tag = tag.unwrap_or("".to_string());
Publisher {
tag,
name,
base_uri,
service_uri,
id_cert
}
}
/// Returns a new Publisher that is the same as this Publisher, except
/// that it has an updated IdCert
pub fn with_new_id_cert(&self, id_cert: IdCert) -> Self {
Publisher {
tag: self.tag.clone(),
name: self.name.clone(),
base_uri: self.base_uri.clone(),
service_uri: self.service_uri.clone(),
id_cert
}
}
}
impl Publisher {
pub fn tag(&self) -> Option<String> {
let tag = &self.tag;
if tag.is_empty() {
None
} else {
Some(tag.clone())
}
}
pub fn name(&self) -> &String {
&self.name
}
pub fn base_uri(&self) -> &uri::Rsync {
&self.base_uri
}
pub fn service_uri(&self) -> &uri::Http {
&self.service_uri
impl Rfc8181PublisherDetails {
pub fn tag(&self) -> &String {
&self.tag
}
pub fn id_cert(&self) -> &IdCert {
@@ -97,12 +35,80 @@ impl Publisher {
}
}
impl Rfc8181PublisherDetails {
pub fn new(tag: Option<String>, id_cert: IdCert) -> Self {
let tag = tag.unwrap_or("".to_string());
Rfc8181PublisherDetails { tag, id_cert }
}
}
impl PartialEq for Rfc8181PublisherDetails {
fn eq(&self, other: &Rfc8181PublisherDetails) -> bool {
self.tag == other.tag &&
self.id_cert.to_bytes() == other.id_cert.to_bytes()
}
}
impl Eq for Rfc8181PublisherDetails {}
//------------ Publisher -----------------------------------------------------
/// This type defines Publisher CAs that are allowed to publish.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Publisher {
handle: String,
/// The token used by the API
token: String,
#[serde(
deserialize_with = "ext_serde::de_rsync_uri",
serialize_with = "ext_serde::ser_rsync_uri")]
base_uri: uri::Rsync,
rfc8181: Option<Rfc8181PublisherDetails>
}
impl Publisher {
pub fn new(
handle: String,
token: String,
base_uri: uri::Rsync,
rfc8181: Option<Rfc8181PublisherDetails>
) -> Self {
Publisher {
handle,
token,
base_uri,
rfc8181
}
}
}
impl Publisher {
pub fn handle(&self) -> &String {
&self.handle
}
pub fn token(&self) -> &String {
&self.token
}
pub fn base_uri(&self) -> &uri::Rsync {
&self.base_uri
}
pub fn rfc8181(&self) -> &Option<Rfc8181PublisherDetails> {
&self.rfc8181
}
}
impl PartialEq for Publisher {
fn eq(&self, other: &Publisher) -> bool {
self.name == other.name &&
self.base_uri == other.base_uri &&
self.service_uri == other.service_uri &&
self.id_cert.to_bytes() == other.id_cert.to_bytes()
self.handle == other.handle &&
self.base_uri == other.base_uri &&
self.rfc8181 == other.rfc8181
}
}
@@ -141,19 +147,7 @@ impl PublisherStore {
)
}
/// Adds a Publisher based on a PublisherRequest (from the RFC 8183 xml).
///
/// Will return an error if the publisher already exists! Use
/// update_publisher in case you want to update an existing publisher.
pub fn add_publisher(
&mut self,
pr: PublisherRequest,
handle: &str,
base_service_uri: &uri::Http,
actor: &str
) -> Result<(), Error> {
let (tag, _, id_cert) = pr.into_parts();
fn verify_handle(&self, handle: &str) -> Result<(), Error> {
if handle.contains("/") {
return Err(Error::ForwardSlashInHandle(handle.to_string()))
}
@@ -162,29 +156,74 @@ impl PublisherStore {
return Err(Error::DuplicatePublisher(handle.to_string()))
}
let mut base_uri = self.base_uri.to_string();
base_uri.push_str(handle);
base_uri.push_str("/");
Ok(())
}
fn publisher_base_uri(&self, handle: &str) -> Result<uri::Rsync, Error> {
let base_uri = format!("{}{}/", self.base_uri.to_string(), handle);
let base_uri = uri::Rsync::from_string(base_uri)?;
Ok(base_uri)
}
let mut service_uri = base_service_uri.to_string();
service_uri.push_str(handle);
let service_uri = uri::Http::from_string(service_uri)?;
/// Adds a Publisher based on a PublisherRequest (from the RFC 8183 xml).
///
/// Will return an error if the publisher already exists! Use
/// update_publisher in case you want to update an existing publisher.
pub fn add_publisher(
&mut self,
prc: PublisherRequestChoice,
handle_override: Option<&str>,
actor: &str
) -> Result<(), Error> {
let key = Key::from_str(handle);
let publisher = match prc {
PublisherRequestChoice::Api(pr) => {
if handle_override.is_some() {
return Err(Error::HandleOverrideNotAllowed)
}
let (handle, token) = pr.parts();
self.verify_handle(&handle)?;
let base_uri = self.publisher_base_uri(&handle)?;
Publisher::new(
handle,
token,
base_uri,
None
)
},
PublisherRequestChoice::Rfc8183(pr) => {
let (tag, mut handle, id_cert) = pr.into_parts();
match handle_override {
Some(handle_override) => {
handle = handle_override.to_string()
},
_ => {}
}
self.verify_handle(&handle)?;
let base_uri = self.publisher_base_uri(&handle)?;
let rfc8181 = Rfc8181PublisherDetails::new(tag, id_cert);
let token = requests::generate_random_token();
Publisher::new(
handle,
token,
base_uri,
Some(rfc8181)
)
}
};
let key = Key::from_str(&publisher.handle);
let info = Info::now(
actor,
&format!("Added publisher: {}", handle)
);
let publisher = Publisher::new(
tag,
handle.to_string(),
base_uri,
service_uri,
id_cert
&format!("Added publisher: {}", &publisher.handle)
);
info!("Adding publisher: {}", handle);
info!("Added publisher: {}", &publisher.handle);
self.store.store(key, publisher, info)?;
Ok(())
@@ -195,10 +234,10 @@ impl PublisherStore {
/// Will return an error if ths publisher does not exist.
pub fn remove_publisher(
&mut self,
name: impl AsRef<str>,
handle: impl AsRef<str>,
actor: &str
) -> Result<(), Error> {
let name = name.as_ref();
let name = handle.as_ref();
match self.publisher(name)? {
None => Err(Error::UnknownPublisher(name.to_string())),
Some(_p) => {
@@ -215,43 +254,15 @@ impl PublisherStore {
}
}
/// Updates the IdCert for a known publisher.
pub fn update_id_cert_publisher(
&mut self,
name: &str,
id_cert: IdCert,
actor: &str
) -> Result<(), Error> {
let publisher_opt = self.publisher(name)?;
match publisher_opt {
None => Err(Error::UnknownPublisher(name.to_string())),
Some(publisher) => {
let key = Key::from_str(name);
let new_publisher = publisher.with_new_id_cert(id_cert);
let info = Info::now(
actor,
"Updated the IdCert"
);
info!("Updated Id for publisher: {}", publisher.name());
self.store.store(key, new_publisher, info)?;
Ok(())
}
}
}
/// Returns whether a publisher exists for this name.
pub fn has_publisher(&self, name: &str) -> bool {
let key = Key::from_str(name);
pub fn has_publisher(&self, handle: &str) -> bool {
let key = Key::from_str(handle);
match self.store.version(&key) {
Ok(Some(version)) => {
if version > 0 {
true
} else {
debug!("Publisher {} was archived.", name);
debug!("Publisher {} was archived.", handle);
false
}
},
@@ -262,9 +273,9 @@ impl PublisherStore {
/// Returns an Optional Arc to a publisher for this name.
pub fn publisher(
&self,
name: impl AsRef<str>
handle: impl AsRef<str>
) -> Result<Option<Arc<Publisher>>, Error> {
let key = Key::from_str(name.as_ref());
let key = Key::from_str(handle.as_ref());
self.store.get(&key).map_err(|e| { Error::KeyStoreError(e)})
}
@@ -272,9 +283,9 @@ impl PublisherStore {
/// does not exist.
pub fn get_publisher(
&self,
name: impl AsRef<str>
handle: impl AsRef<str>
) -> Result<Arc<Publisher>, Error> {
let name = name.as_ref();
let name = handle.as_ref();
match self.publisher(name)? {
None => Err(Error::UnknownPublisher(name.to_string())),
Some(p) => Ok(p)
@@ -324,8 +335,11 @@ pub enum Error {
#[display(fmt = "Error in base URI: {}.", _0)]
UriError(uri::Error),
#[display(fmt = "Invalide Publisher Request: {}.", _0)]
PublisherRequestError(PublisherRequestError)
#[display(fmt = "Invalid Publisher Request: {}.", _0)]
PublisherRequestError(rfc8183::PublisherRequestError),
#[display(fmt = "Cannot override handle using path parameter for json api")]
HandleOverrideNotAllowed
}
impl From<keystore::Error> for Error {
@@ -346,8 +360,8 @@ impl From<uri::Error> for Error {
}
}
impl From<PublisherRequestError> for Error {
fn from(e: PublisherRequestError) -> Self {
impl From<rfc8183::PublisherRequestError> for Error {
fn from(e: rfc8183::PublisherRequestError) -> Self {
Error::PublisherRequestError(e)
}
}
@@ -361,10 +375,6 @@ mod tests {
use super::*;
use crate::util::test;
fn base_service_uri() -> uri::Http {
test::http_uri("http://127.0.0.1:3000/rfc8181/")
}
fn test_publisher_store(dir: &PathBuf) -> PublisherStore {
let uri = test::rsync_uri("rsync://host/module/");
PublisherStore::new(dir, &uri).unwrap()
@@ -375,10 +385,11 @@ mod tests {
test::test_with_tmp_dir(|d| {
let mut ps = test_publisher_store(&d);
let pr = test::new_publisher_request("test/below", &d);
let prc = PublisherRequestChoice::Rfc8183(pr);
let handle = "test/below";
match ps.add_publisher(pr, handle, &base_service_uri(), "test") {
match ps.add_publisher(prc, Some(handle), "test") {
Err(Error::ForwardSlashInHandle(_)) => { }, // Ok
_ => panic!("Should have seen error.")
}
@@ -390,27 +401,29 @@ mod tests {
test::test_with_tmp_dir(|d| {
let mut ps = test_publisher_store(&d);
let name = "alice";
let pr = test::new_publisher_request(name, &d);
let id_cert = pr.id_cert().clone();
let prc = PublisherRequestChoice::Rfc8183(pr);
let actor = "test";
ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap();
ps.add_publisher(prc, Some(name), actor).unwrap();
assert!(ps.has_publisher(&name));
// Get the Arc out of the Result<Option<Arc<Publisher>>, Error>
let publisher_found = ps.publisher(&name).unwrap().unwrap();
let expected_publisher = Publisher::new(
None,
name.to_string(),
test::rsync_uri(&format!("rsync://host/module/{}/", name)),
test::http_uri(
&format!("http://127.0.0.1:3000/rfc8181/{}",name)),
id_cert
);
let expected_rfc8181 = Rfc8181PublisherDetails::new(None, id_cert);
assert_eq!(publisher_found.handle(), "alice");
assert_eq!(
publisher_found.base_uri().to_string().as_str(),
"rsync://host/module/alice/");
assert_eq!(publisher_found.rfc8181(), &Some(expected_rfc8181));
assert_eq!(publisher_found.as_ref(), &expected_publisher);
})
}
@@ -420,13 +433,15 @@ mod tests {
let mut ps = test_publisher_store(&d);
let name = "alice";
let pr = test::new_publisher_request(name, &d);
let prc = PublisherRequestChoice::Rfc8183(pr);
let actor = "test";
ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap();
ps.add_publisher(prc, None, actor).unwrap();
assert!(ps.has_publisher(&name));
let pr = test::new_publisher_request(name, &d);
match ps.add_publisher(pr, name, &base_service_uri(), actor) {
let prc = PublisherRequestChoice::Rfc8183(pr);
match ps.add_publisher(prc, None, actor) {
Err(Error::DuplicatePublisher(_)) => { }, // Ok
_ => panic!("Should have seen error.")
}
@@ -434,42 +449,6 @@ mod tests {
}
#[test]
fn should_update_id_cert_publisher() {
test::test_with_tmp_dir(|d| {
let mut ps = test_publisher_store(&d);
let name = "alice";
let pr = test::new_publisher_request(name, &d);
let actor = "test";
ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap();
// Make a new publisher request for alice, using a new cert
let pr = test::new_publisher_request(name, &d);
let id_cert = pr.id_cert().clone();
ps.update_id_cert_publisher(
name,
id_cert.clone(),
actor.clone()
).unwrap();
// Get the Arc out of the Result<Option<Arc<Publisher>>, Error>
let publisher_found = ps.publisher(&name).unwrap().unwrap();
let expected_publisher = Publisher::new(
None,
name.to_string(),
test::rsync_uri(&format!("rsync://host/module/{}/", name)),
test::http_uri(
&format!("http://127.0.0.1:3000/rfc8181/{}",name)),
id_cert
);
assert_eq!(publisher_found.as_ref(), &expected_publisher);
})
}
#[test]
fn should_remove_publisher() {
test::test_with_tmp_dir(|d| {
@@ -478,8 +457,9 @@ mod tests {
let name = "alice";
let actor = "test";
let pr = test::new_publisher_request(name, &d);
let prc = PublisherRequestChoice::Rfc8183(pr);
ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap();
ps.add_publisher(prc, None, actor).unwrap();
assert_eq!(1, ps.publishers().unwrap(). len());
ps.remove_publisher(name, actor).unwrap();
+4 -5
View File
@@ -63,11 +63,11 @@ impl Repository {
&mut self,
delta: &PublishDelta,
base_uri: &uri::Rsync
) -> Result<responses::PublishReply, Error> {
) -> Result<(), Error> {
debug!("Processing update with {} elements", delta.len());
self.fs.publish(delta, base_uri)?;
self.rrdp.publish(delta)?;
Ok(responses::PublishReply::Success)
Ok(())
}
/// Lists the objects for a base_uri, presumably all for the same
@@ -75,11 +75,10 @@ impl Repository {
pub fn list(
&self,
base_uri: &uri::Rsync
) -> Result<responses::PublishReply, Error> {
) -> Result<responses::ListReply, Error> {
debug!("Processing list query");
let files = self.fs.list(base_uri)?;
Ok(responses::PublishReply::List(
responses::ListReply::new(files)))
Ok(responses::ListReply::new(files))
}
}
+1
View File
@@ -20,6 +20,7 @@ extern crate serde_json;
extern crate syslog;
extern crate tokio;
extern crate toml;
extern crate uuid;
extern crate xml as xmlrs;
// XXX Temporarily
+15 -11
View File
@@ -29,23 +29,15 @@ use crate::remote::sigmsg::SignedMessage;
pub struct CmsProxy {
// The component that manages server id, and wraps responses to clients
responder: Responder,
// The URI that publishers need to access to publish (see config)
service_uri: uri::Http,
}
/// # Set up
impl CmsProxy {
pub fn new(
work_dir: &PathBuf,
service_uri: &uri::Http
work_dir: &PathBuf
) -> Result<Self, Error> {
let responder = Responder::init(work_dir)?;
Ok(CmsProxy { responder, service_uri: service_uri.clone() })
}
pub fn base_service_uri(&self) -> &uri::Http {
&self.service_uri
Ok(CmsProxy { responder })
}
}
@@ -107,10 +99,22 @@ impl CmsProxy {
pub fn repository_response(
&self,
publisher: Arc<Publisher>,
base_service_uri: &uri::Http,
rrdp_notification_uri: uri::Http
) -> Result<rfc8183::RepositoryResponse, Error> {
let service_uri = format!(
"{}rfc8181/{}",
base_service_uri.to_string(),
publisher.handle()
);
let service_uri = uri::Http::from_string(service_uri).unwrap();
self.responder
.repository_response(publisher, rrdp_notification_uri)
.repository_response(
publisher,
service_uri,
rrdp_notification_uri)
.map_err(|e| Error::ResponderError(e))
}
+24 -9
View File
@@ -96,20 +96,26 @@ impl Responder {
pub fn repository_response(
&self,
publisher: Arc<Publisher>,
service_uri: uri::Http,
rrdp_notification_uri: uri::Http
) -> Result<RepositoryResponse, Error> {
if let Some(my_id) = self.my_identity()? {
let tag = publisher.tag();
let publisher_handle = publisher.name().clone();
let tag = match publisher.rfc8181() {
Some(details) => Some(details.tag().clone()),
None => return Err(Error::ClientUnitialised)
};
let handle = publisher.handle();
let id_cert = my_id.id_cert().clone();
let service_uri = publisher.service_uri().clone();
let sia_base = publisher.base_uri().clone();
Ok(
RepositoryResponse::new(
tag,
publisher_handle,
handle.clone(),
id_cert,
service_uri,
sia_base,
@@ -156,6 +162,9 @@ pub enum Error {
#[display(fmt="Identity of server is not initialised.")]
Unitialised,
#[display(fmt="Identity of client is not initialised.")]
ClientUnitialised,
}
impl From<io::Error> for Error {
@@ -188,6 +197,7 @@ impl From<builder::Error<softsigner::SignerError>> for Error {
mod tests {
use super::*;
use crate::util::test;
use daemon::publishers::Rfc8181PublisherDetails;
#[test]
fn should_have_response_for_publisher() {
@@ -202,17 +212,22 @@ mod tests {
let base_uri = test::rsync_uri("rsync://host/module/alice/");
let service_uri = test::http_uri("http://127.0.0.1:3000/rfc8181/alice");
let rfc8181 = Rfc8181PublisherDetails::new(tag, id_cert);
let publisher = Arc::new(Publisher::new(
tag,
name,
"token".to_string(),
base_uri,
service_uri,
id_cert
Some(rfc8181)
));
let rrdp_uri = test::http_uri("http://host/rrdp/");
responder.repository_response(publisher, rrdp_uri).unwrap();
responder.repository_response(
publisher,
service_uri,
rrdp_uri
).unwrap();
});
}
-1
View File
@@ -78,7 +78,6 @@ fn client_publish_at_server() {
res.text().unwrap().as_bytes()
).unwrap();
repo_res.validate().unwrap();
client.process_repo_response(repo_res).unwrap();