Commit c10de0c3 authored by Nick Mathewson's avatar Nick Mathewson 👁
Browse files

Add builders for authority and fallback objects.

parent c72193bd
......@@ -3,6 +3,7 @@
//! From a client's point of view, an authority's role is to to sign the
//! consensus directory.
use crate::{Error, Result};
use serde::Deserialize;
use tor_llcrypto::pk::rsa::RsaIdentity;
use tor_netdoc::doc::authcert::{AuthCert, AuthCertKeyIds};
......@@ -23,11 +24,18 @@ pub struct Authority {
}
impl Authority {
/// Construct information about a new authority.
pub fn new(name: String, v3ident: RsaIdentity) -> Self {
Authority { name, v3ident }
/// Return a new builder for constructing an [`Authority`].
///
/// You only need this if you're using a non-default Tor network
/// with its own set of directory authorities.
pub fn builder() -> AuthorityBuilder {
AuthorityBuilder::new()
}
/// Return the v3 identity key of this certificate.
///
/// This is the identity of the >=2048-bit RSA key that the
/// authority uses to sign documents; it is distinct from its
/// identity keys that it uses when operating as a relay.
pub fn v3ident(&self) -> &RsaIdentity {
&self.v3ident
}
......@@ -46,11 +54,14 @@ impl Authority {
pub(crate) fn default_authorities() -> Vec<Authority> {
/// Build an authority; panic if input is bad.
fn auth(name: &str, key: &str) -> Authority {
let name = name.to_string();
let v3ident = hex::decode(key).expect("Built-in authority identity had bad hex!?");
let v3ident = RsaIdentity::from_bytes(&v3ident)
.expect("Built-in authority identity had wrong length!?");
Authority { name, v3ident }
AuthorityBuilder::new()
.name(name)
.v3ident(v3ident)
.build()
.expect("unable to construct built-in authority!?")
}
// (List generated August 2020.)
......@@ -67,6 +78,48 @@ pub(crate) fn default_authorities() -> Vec<Authority> {
]
}
/// A Builder object for constructing an [`Authority`] entry.
#[derive(Debug, Clone, Default)]
pub struct AuthorityBuilder {
/// See [`Authority::name`]
name: Option<String>,
/// See [`Authority::v3ident`]
v3ident: Option<RsaIdentity>,
}
impl AuthorityBuilder {
/// Make a new AuthorityBuilder with no fields set.
pub fn new() -> Self {
Self::default()
}
/// Set the name on this AuthorityBuilder.
///
/// This field is required.
pub fn name(&mut self, name: &str) -> &mut Self {
self.name = Some(name.to_owned());
self
}
/// Set the v3 RSA identity of this AuthorityBuilder.
///
/// This field is required.
pub fn v3ident(&mut self, key: RsaIdentity) -> &mut Self {
self.v3ident = Some(key);
self
}
/// Try to build an [`Authority`].
pub fn build(&self) -> Result<Authority> {
let name = self
.name
.as_ref()
.ok_or(Error::BadNetworkConfig("Missing authority name"))?
.clone();
let v3ident = self
.v3ident
.ok_or(Error::BadNetworkConfig("Missing v3 identity key."))?;
Ok(Authority { name, v3ident })
}
}
#[cfg(test)]
mod test {
use super::*;
......@@ -74,7 +127,11 @@ mod test {
fn authority() {
let key1: RsaIdentity = [9_u8; 20].into();
let key2: RsaIdentity = [10_u8; 20].into();
let auth = Authority::new("example".into(), key1.clone());
let auth = Authority::builder()
.name("example")
.v3ident(key1)
.build()
.unwrap();
assert_eq!(auth.v3ident(), &key1);
......
......@@ -152,39 +152,43 @@ impl NetDirConfigBuilder {
}
/// Set the network information (authorities and fallbacks) from `config`.
pub fn set_network_config(&mut self, config: NetworkConfig) {
pub fn set_network_config(&mut self, config: NetworkConfig) -> &mut Self {
self.network = config;
self
}
/// Set the timining information that we use for deciding when to
/// attempt and retry downloads.
pub fn set_timing_config(&mut self, timing: DownloadScheduleConfig) {
pub fn set_timing_config(&mut self, timing: DownloadScheduleConfig) -> &mut Self {
self.timing = timing;
self
}
/// Use `path` as the directory to use for current directory files.
pub fn set_cache_path(&mut self, path: &Path) {
pub fn set_cache_path(&mut self, path: &Path) -> &mut Self {
self.cache_path = Some(path.to_path_buf());
self
}
/// Try to use the default cache path.
///
/// This will be ~/.cache/arti on unix, and in other suitable
/// locations on other platforms.
pub fn use_default_cache_path(&mut self) -> Result<()> {
pub fn use_default_cache_path(&mut self) -> Result<&mut Self> {
let pd = directories::ProjectDirs::from("org", "torproject", "Arti")
.ok_or(Error::DirectoryNotPresent)?;
self.cache_path = Some(pd.cache_dir().into());
Ok(())
Ok(self)
}
/// Consume this builder and return a NetDirConfig that can be used
/// Use this builder to produce a NetDirConfig that can be used
/// to load directories
pub fn finalize(self) -> Result<NetDirConfig> {
pub fn finalize(&self) -> Result<NetDirConfig> {
let cache_path = self
.cache_path
.as_ref()
.ok_or(Error::BadNetworkConfig("No cache path configured"))?;
if self.network.authority.is_empty() {
......@@ -195,9 +199,9 @@ impl NetDirConfigBuilder {
}
Ok(NetDirConfig {
cache_path,
network: self.network,
timing: self.timing,
cache_path: cache_path.clone(),
network: self.network.clone(),
timing: self.timing.clone(),
})
}
}
......@@ -279,12 +283,41 @@ mod fallbacks {
.expect("Bad hex in built-in fallback list");
let ed =
Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
let ports = ports
let mut bld = FallbackDir::builder();
bld.rsa_identity(rsa).ed_identity(ed);
ports
.iter()
.map(|s| s.parse().expect("Bad socket address in fallbacklist"))
.collect();
FallbackDir::new(rsa, ed, ports)
.for_each(|p| {
bld.orport(p);
});
bld.build()
.expect("Unable to build default fallback directory!?")
}
include!("fallback_dirs.inc")
}
}
#[cfg(test)]
mod test {
use super::*;
use tempdir::TempDir;
#[test]
fn simplest_config() -> Result<()> {
let tmp = TempDir::new("arti-config").unwrap();
let dir = NetDirConfigBuilder::new()
.set_cache_path(tmp.path())
.finalize()?;
assert!(dir.authorities().len() >= 3);
assert!(dir.fallbacks().len() >= 3);
// TODO: verify other defaults.
Ok(())
}
}
......@@ -5,6 +5,8 @@
//! "Fallback Directory" to retreive its initial information about the
//! network.
use crate::{Error, Result};
use tor_llcrypto::pk::ed25519::Ed25519Identity;
use tor_llcrypto::pk::rsa::RsaIdentity;
......@@ -28,18 +30,71 @@ pub struct FallbackDir {
orports: Vec<SocketAddr>,
}
/// A Builder object for constructing a [`FallbackDir`].
#[derive(Debug, Clone, Default)]
pub struct FallbackDirBuilder {
/// See [`FallbackDir::rsa_identity`]
rsa_identity: Option<RsaIdentity>,
/// See [`FallbackDir::ed_identity`]
ed_identity: Option<Ed25519Identity>,
/// See [`FallbackDir::orports`]
orports: Vec<SocketAddr>,
}
impl FallbackDir {
/// Construct a new FallbackDir
pub fn new(
rsa_identity: RsaIdentity,
ed_identity: Ed25519Identity,
orports: Vec<SocketAddr>,
) -> Self {
FallbackDir {
rsa_identity,
ed_identity,
orports,
/// Return a builder that can be used to make a `FallbackDir`.
pub fn builder() -> FallbackDirBuilder {
FallbackDirBuilder::new()
}
}
impl FallbackDirBuilder {
/// Make a new FallbackDirBuilder.
///
/// You only need to use this if you're using a non-default set of
/// fallback directories.
pub fn new() -> Self {
Self::default()
}
/// Set the RSA identity for this fallback directory.
///
/// This field is required.
pub fn rsa_identity(&mut self, rsa_identity: RsaIdentity) -> &mut Self {
self.rsa_identity = Some(rsa_identity);
self
}
/// Set the Ed25519 identity for this fallback directory.
///
/// This field is required.
pub fn ed_identity(&mut self, ed_identity: Ed25519Identity) -> &mut Self {
self.ed_identity = Some(ed_identity);
self
}
/// Add a single OR port for this fallback directory.
///
/// This field is required, and may be called more than once.
pub fn orport(&mut self, orport: SocketAddr) -> &mut Self {
self.orports.push(orport);
self
}
/// Try to construct a [`FallbackDir`] from this builder.
pub fn build(&self) -> Result<FallbackDir> {
let rsa_identity = self.rsa_identity.as_ref().ok_or(Error::BadArgument(
"Missing RSA identity on fallback directory",
))?;
let ed_identity = self.ed_identity.as_ref().ok_or(Error::BadArgument(
"Missing ed25519 identity on fallback directory",
))?;
let orports = self.orports.clone();
if orports.is_empty() {
return Err(Error::BadArgument("No OR ports on fallback directory"));
}
Ok(FallbackDir {
rsa_identity: *rsa_identity,
ed_identity: *ed_identity,
orports,
})
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment