blob: eedbbf7b8fc031b5da14dd20b9169fdca97f15e3 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
failure::{format_err, Error},
fidl_fuchsia_amber as fidl,
serde_derive::{Deserialize, Serialize},
std::{
convert::{TryFrom, TryInto},
fmt,
},
};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SourceConfigBuilder {
config: SourceConfig,
}
impl SourceConfigBuilder {
pub fn new(id: impl Into<String>) -> Self {
Self {
config: SourceConfig {
id: id.into(),
repo_url: "".to_string(),
blob_repo_url: "".to_string(),
rate_limit: 0,
rate_period: 0,
root_keys: vec![],
transport_config: None,
status_config: Some(StatusConfig { enabled: true }),
auto: false,
blob_key: None,
},
}
}
pub fn repo_url(mut self, value: impl Into<String>) -> Self {
self.config.repo_url = value.into();
self.config.blob_repo_url = format!("{}/blobs", self.config.repo_url);
self
}
pub fn rate_period(mut self, value: i32) -> Self {
self.config.rate_period = value;
self
}
pub fn auto(mut self, value: bool) -> Self {
self.config.auto = value;
self
}
pub fn add_root_key(mut self, value: &str) -> Self {
self.config.root_keys.push(KeyConfig::Ed25519(hex::decode(value).unwrap()));
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.config.status_config = Some(StatusConfig { enabled });
self
}
pub fn build(self) -> SourceConfig {
self.config
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SourceConfig {
id: String,
#[serde(rename = "repoURL")]
repo_url: String,
#[serde(rename = "blobRepoURL")]
blob_repo_url: String,
#[serde(default, rename = "rateLimit")]
rate_limit: u64,
#[serde(default, rename = "ratePeriod")]
rate_period: i32,
#[serde(rename = "rootKeys")]
root_keys: Vec<KeyConfig>,
#[serde(rename = "transportConfig")]
transport_config: Option<TransportConfig>,
#[serde(rename = "statusConfig")]
status_config: Option<StatusConfig>,
auto: bool,
#[serde(rename = "blobKey")]
blob_key: Option<BlobEncryptionKey>,
}
impl SourceConfig {
pub fn id(&self) -> &str {
self.id.as_str()
}
}
impl Into<fidl::SourceConfig> for SourceConfig {
fn into(self) -> fidl::SourceConfig {
fidl::SourceConfig {
id: self.id,
repo_url: self.repo_url,
blob_repo_url: self.blob_repo_url,
rate_limit: self.rate_limit,
rate_period: self.rate_period,
root_keys: self.root_keys.into_iter().map(|key| key.into()).collect(),
transport_config: self.transport_config.map(|cfg| Box::new(cfg.into())),
oauth2_config: None,
status_config: self.status_config.map(|cfg| Box::new(cfg.into())),
auto: self.auto,
blob_key: self.blob_key.map(|key| Box::new(key.into())),
}
}
}
impl TryFrom<fidl::SourceConfig> for SourceConfig {
type Error = Error;
fn try_from(x: fidl::SourceConfig) -> Result<Self, Self::Error> {
if x.oauth2_config.is_some() {
return Err(format_err!("oauth2_config is not supported"));
}
Ok(SourceConfig {
id: x.id,
repo_url: x.repo_url,
blob_repo_url: x.blob_repo_url,
rate_limit: x.rate_limit,
rate_period: x.rate_period,
root_keys: x
.root_keys
.into_iter()
.map(|key| key.try_into())
.collect::<Result<Vec<_>, _>>()?,
transport_config: x.transport_config.map(|cfg| cfg.try_into()).transpose()?,
status_config: x.status_config.map(|cfg| cfg.try_into()).transpose()?,
auto: x.auto,
blob_key: x.blob_key.map(|key| key.try_into()).transpose()?,
})
}
}
impl Ord for SourceConfig {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for SourceConfig {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TransportConfig {
disable_keep_alives: bool,
keep_alive: i32,
max_idle_conns: i32,
max_idle_conns_per_host: i32,
connect_timeout: i32,
request_timeout: i32,
idle_conn_timeout: i32,
response_header_timeout: i32,
expect_continue_timeout: i32,
tls_handshake_timeout: i32,
}
impl Into<fidl::TransportConfig> for TransportConfig {
fn into(self) -> fidl::TransportConfig {
fidl::TransportConfig {
disable_keep_alives: self.disable_keep_alives,
keep_alive: self.keep_alive,
max_idle_conns: self.max_idle_conns,
max_idle_conns_per_host: self.max_idle_conns_per_host,
connect_timeout: self.connect_timeout,
request_timeout: self.request_timeout,
idle_conn_timeout: self.idle_conn_timeout,
response_header_timeout: self.response_header_timeout,
expect_continue_timeout: self.expect_continue_timeout,
tls_handshake_timeout: self.tls_handshake_timeout,
tls_client_config: None,
}
}
}
impl TryFrom<Box<fidl::TransportConfig>> for TransportConfig {
type Error = Error;
fn try_from(x: Box<fidl::TransportConfig>) -> Result<Self, Self::Error> {
if x.tls_client_config.is_some() {
return Err(format_err!("tls_client_config not supported"));
}
Ok(TransportConfig {
disable_keep_alives: x.disable_keep_alives,
keep_alive: x.keep_alive,
max_idle_conns: x.max_idle_conns,
max_idle_conns_per_host: x.max_idle_conns_per_host,
connect_timeout: x.connect_timeout,
request_timeout: x.request_timeout,
idle_conn_timeout: x.idle_conn_timeout,
response_header_timeout: x.response_header_timeout,
expect_continue_timeout: x.expect_continue_timeout,
tls_handshake_timeout: x.tls_handshake_timeout,
})
}
}
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase", tag = "type", content = "value", deny_unknown_fields)]
pub enum KeyConfig {
Ed25519(#[serde(with = "hex_serde")] Vec<u8>),
}
impl Into<fidl::KeyConfig> for KeyConfig {
fn into(self) -> fidl::KeyConfig {
let KeyConfig::Ed25519(value) = self;
fidl::KeyConfig { type_: "ed25519".to_owned(), value: hex::encode(value) }
}
}
impl TryFrom<fidl::KeyConfig> for KeyConfig {
type Error = Error;
fn try_from(x: fidl::KeyConfig) -> Result<Self, Self::Error> {
if x.type_ != "ed25519" {
return Err(format_err!("unknown key type: {}", x.type_));
}
Ok(KeyConfig::Ed25519(hex::decode(x.value.as_bytes())?))
}
}
impl fmt::Debug for KeyConfig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let KeyConfig::Ed25519(ref value) = self;
f.write_str(&hex::encode(value))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct StatusConfig {
enabled: bool,
}
impl Into<fidl::StatusConfig> for StatusConfig {
fn into(self) -> fidl::StatusConfig {
fidl::StatusConfig { enabled: self.enabled }
}
}
impl TryFrom<Box<fidl::StatusConfig>> for StatusConfig {
type Error = Error;
fn try_from(x: Box<fidl::StatusConfig>) -> Result<Self, Self::Error> {
Ok(StatusConfig { enabled: x.enabled })
}
}
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BlobEncryptionKey {
data: [u8; 32],
}
impl Into<fidl::BlobEncryptionKey> for BlobEncryptionKey {
fn into(self) -> fidl::BlobEncryptionKey {
fidl::BlobEncryptionKey { data: self.data }
}
}
impl TryFrom<Box<fidl::BlobEncryptionKey>> for BlobEncryptionKey {
type Error = Error;
fn try_from(x: Box<fidl::BlobEncryptionKey>) -> Result<Self, Self::Error> {
Ok(BlobEncryptionKey { data: x.data })
}
}
impl fmt::Debug for BlobEncryptionKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&hex::encode(self.data))
}
}
mod hex_serde {
use {hex, serde::Deserialize};
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s = hex::encode(bytes);
serializer.serialize_str(&s)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
hex::decode(value.as_bytes())
.map_err(|e| serde::de::Error::custom(format!("bad hex value: {:?}: {}", value, e)))
}
}