1
0
mirror of https://github.com/vbrandl/bind9-api.git synced 2024-11-22 11:13:49 +01:00

Add documentation and fail builds on missing docs

This commit is contained in:
Valentin Brandl 2018-07-08 20:28:50 +02:00
parent 6eacab00f9
commit 9ec59bf5e3
Signed by: vbrandl
GPG Key ID: CAD4DA1A789125F9
2 changed files with 212 additions and 6 deletions

View File

@ -38,6 +38,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#![deny(missing_docs)]
//! Helper crate for cryptographic operations.
extern crate failure; extern crate failure;
extern crate hex; extern crate hex;
@ -53,16 +56,19 @@ use ring::{digest, hmac};
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
/// Converts a byte slice to a lowercase hex string.
pub fn bytes_to_hex_str(bytes: &[u8]) -> Result<String> { pub fn bytes_to_hex_str(bytes: &[u8]) -> Result<String> {
let mut output = String::new(); let mut output = String::new();
bytes.write_hex(&mut output)?; bytes.write_hex(&mut output)?;
Ok(output) Ok(output)
} }
/// Converts a hey string to a vec of bytes.
pub fn hex_str_to_bytes(hex_str: &str) -> Result<Vec<u8>> { pub fn hex_str_to_bytes(hex_str: &str) -> Result<Vec<u8>> {
Ok(Vec::from_hex(hex_str)?) Ok(Vec::from_hex(hex_str)?)
} }
/// Verifies a HMAC SHA256 signature.
pub fn verify_signature(key: &[u8], msg: &[u8], signature: &[u8]) -> bool { pub fn verify_signature(key: &[u8], msg: &[u8], signature: &[u8]) -> bool {
let key = hmac::VerificationKey::new(&digest::SHA256, key); let key = hmac::VerificationKey::new(&digest::SHA256, key);
hmac::verify(&key, msg, signature) hmac::verify(&key, msg, signature)
@ -70,6 +76,7 @@ pub fn verify_signature(key: &[u8], msg: &[u8], signature: &[u8]) -> bool {
.unwrap_or(false) .unwrap_or(false)
} }
/// Creates a HMAC SHA256 signature.
pub fn sign(key: &[u8], msg: &[u8]) -> Vec<u8> { pub fn sign(key: &[u8], msg: &[u8]) -> Vec<u8> {
let key = hmac::SigningKey::new(&digest::SHA256, key); let key = hmac::SigningKey::new(&digest::SHA256, key);
let signature = hmac::sign(&key, msg); let signature = hmac::sign(&key, msg);

View File

@ -38,30 +38,110 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#![deny(missing_docs)]
//! This crate provides definitions for shared types between the client and the server
#[macro_use] #[macro_use]
extern crate failure; extern crate failure;
#[macro_use] #[macro_use]
extern crate hyper;
#[macro_use]
extern crate serde_derive; extern crate serde_derive;
/// The name of the API token header: `X-Api-Token`
pub const TOKEN_HEADER: &str = "X-Api-Token"; pub const TOKEN_HEADER: &str = "X-Api-Token";
header! { (XApiToken, TOKEN_HEADER) => [String] } /// Enumeration of DNS record types
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug, Clone, Copy)] #[derive(Eq, PartialEq, Deserialize, Serialize, Debug, Clone, Copy)]
pub enum Record { pub enum Record {
/// A record
A, A,
/// AAAA record
AAAA, AAAA,
/// AFSDB record
AFSDB,
/// APL record
APL,
/// CAA record
CAA,
/// CDNSKEY record
CDNSKEY,
/// CDS record
CDS,
/// CERT record
CERT,
/// CNAME record
CNAME,
/// DHCID record
DHCID,
/// DLV record
DLV,
/// DNAME record
DNAME,
/// DNSKEY record
DNSKEY,
/// DS record
DS,
/// HIP record
HIP,
/// IPSECKEY record
IPSECKEY,
/// KEY record
KEY,
/// KX record
KX,
/// LOC record
LOC,
/// MX record
MX,
/// NAPTR record
NAPTR,
/// NS record
NS,
/// NSEC record
NSEC,
/// NSEC3 record
NSEC3,
/// NSEC3PARAM record
NSEC3PARAM,
/// OPENPGPKEY record
OPENPGPKEY,
/// PTR record
PTR, PTR,
/// RRSIG record
RRSIG,
/// RP record
RP,
/// SIG record
SIG,
/// SOA record
SOA,
/// SRV record
SRV,
/// SSHFP record
SSHFP,
/// TA record
TA,
/// TKEY record
TKEY,
/// TLSA record
TLSA,
/// TSIG record
TSIG,
/// TXT record
TXT, TXT,
/// URI record
URI,
/// ALIAS record
ALIAS,
} }
/// Error types that the API can yield
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum ApiError { pub enum ApiError {
/// Error while parsing a DNS record
#[fail(display = "Parse record error")] #[fail(display = "Parse record error")]
ParseRecord, ParseRecord,
/// Error while handling a request
#[fail(display = "API Error")] #[fail(display = "API Error")]
RequestError, RequestError,
} }
@ -73,8 +153,44 @@ impl std::str::FromStr for Record {
match s { match s {
"A" | "a" => Ok(Record::A), "A" | "a" => Ok(Record::A),
"AAAA" | "aaaa" => Ok(Record::AAAA), "AAAA" | "aaaa" => Ok(Record::AAAA),
"TXT" | "txt" => Ok(Record::TXT), "AFSDB" | "afsdb" => Ok(Record::AFSDB),
"APL" | "apl" => Ok(Record::APL),
"CAA" | "caa" => Ok(Record::CAA),
"CDNSKEY" | "cdnskey" => Ok(Record::CDNSKEY),
"CDS" | "cds" => Ok(Record::CDS),
"CERT" | "cert" => Ok(Record::CERT),
"CNAME" | "cname" => Ok(Record::CNAME),
"DHCID" | "dhcid" => Ok(Record::DHCID),
"DLV" | "dlv" => Ok(Record::DLV),
"DNAME" | "dname" => Ok(Record::DNAME),
"DNSKEY" | "dnskey" => Ok(Record::DNSKEY),
"DS" | "ds" => Ok(Record::DS),
"HIP" | "hip" => Ok(Record::HIP),
"IPSECKEY" | "ipseckey" => Ok(Record::IPSECKEY),
"KEY" | "key" => Ok(Record::KEY),
"KX" | "kx" => Ok(Record::KX),
"LOC" | "loc" => Ok(Record::LOC),
"MX" | "mx" => Ok(Record::MX),
"NAPTR" | "naptr" => Ok(Record::NAPTR),
"NS" | "ns" => Ok(Record::NS),
"NSEC" | "nsec" => Ok(Record::NSEC),
"NSEC3" | "nsec3" => Ok(Record::NSEC3),
"NSEC3PARAM" | "nsec3param" => Ok(Record::NSEC3PARAM),
"OPENPGPKEY" | "openpgpkey" => Ok(Record::OPENPGPKEY),
"PTR" | "ptr" => Ok(Record::PTR), "PTR" | "ptr" => Ok(Record::PTR),
"RRSIG" | "rrsig" => Ok(Record::RRSIG),
"RP" | "rp" => Ok(Record::RP),
"SIG" | "sig" => Ok(Record::SIG),
"SOA" | "soa" => Ok(Record::SOA),
"SRV" | "srv" => Ok(Record::SRV),
"SSHFP" | "sshfp" => Ok(Record::SSHFP),
"TA" | "ta" => Ok(Record::TA),
"TKEY" | "tkey" => Ok(Record::TKEY),
"TLSA" | "tlsa" => Ok(Record::TLSA),
"TSIG" | "tsig" => Ok(Record::TSIG),
"TXT" | "txt" => Ok(Record::TXT),
"URI" | "uri" => Ok(Record::URI),
"ALIAS" | "alias" => Ok(Record::ALIAS),
_ => Err(ApiError::ParseRecord), _ => Err(ApiError::ParseRecord),
} }
} }
@ -88,13 +204,51 @@ impl std::fmt::Display for Record {
match *self { match *self {
Record::A => "A", Record::A => "A",
Record::AAAA => "AAAA", Record::AAAA => "AAAA",
Record::AFSDB => "AFSDB",
Record::APL => "APL",
Record::CAA => "CAA",
Record::CDNSKEY => "CDNSKEY",
Record::CDS => "CDS",
Record::CERT => "CERT",
Record::CNAME => "CNAME",
Record::DHCID => "DHCID",
Record::DLV => "DLV",
Record::DNAME => "DNAME",
Record::DNSKEY => "DNSKEY",
Record::DS => "DS",
Record::HIP => "HIP",
Record::IPSECKEY => "IPSECKEY",
Record::KEY => "KEY",
Record::KX => "KX",
Record::LOC => "LOC",
Record::MX => "MX",
Record::NAPTR => "NAPTR",
Record::NS => "NS",
Record::NSEC => "NSEC",
Record::NSEC3 => "NSEC3",
Record::NSEC3PARAM => "NSEC3PARAM",
Record::OPENPGPKEY => "OPENPGPKEY",
Record::PTR => "PTR", Record::PTR => "PTR",
Record::RRSIG => "RRSIG",
Record::RP => "RP",
Record::SIG => "SIG",
Record::SOA => "SOA",
Record::SRV => "SRV",
Record::SSHFP => "SSHFP",
Record::TA => "TA",
Record::TKEY => "TKEY",
Record::TLSA => "TLSA",
Record::TSIG => "TSIG",
Record::TXT => "TXT", Record::TXT => "TXT",
Record::URI => "URI",
Record::ALIAS => "ALIAS",
} }
) )
} }
} }
/// Data for an update request containing the domain name, record type,
/// record value and TTL.
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Update { pub struct Update {
name: String, name: String,
@ -104,36 +258,42 @@ pub struct Update {
} }
impl Update { impl Update {
/// Creates a new Update object.
pub fn new(name: String, value: String, record: Record, ttl: u32) -> Self { pub fn new(name: String, value: String, record: Record, ttl: u32) -> Self {
Self { Self {
name, name,
value, value,
record, record,
ttl: ttl, ttl,
} }
} }
/// Returns a reference to the name field.
#[inline] #[inline]
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
/// Returns a reference to the value field.
#[inline] #[inline]
pub fn value(&self) -> &str { pub fn value(&self) -> &str {
&self.value &self.value
} }
/// Returns the record field.
#[inline] #[inline]
pub fn record(&self) -> Record { pub fn record(&self) -> Record {
self.record self.record
} }
/// Returns the TTL.
#[inline] #[inline]
pub fn ttl(&self) -> u32 { pub fn ttl(&self) -> u32 {
self.ttl self.ttl
} }
} }
/// Data of a delete request, containing the domain name and record type.
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Delete { pub struct Delete {
name: String, name: String,
@ -141,15 +301,18 @@ pub struct Delete {
} }
impl Delete { impl Delete {
/// Creates a new Delete object.
pub fn new(name: String, record: Record) -> Self { pub fn new(name: String, record: Record) -> Self {
Self { name, record } Self { name, record }
} }
/// Returns a reference to the name field.
#[inline] #[inline]
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
/// Returns the record type.
#[inline] #[inline]
pub fn record(&self) -> Record { pub fn record(&self) -> Record {
self.record self.record
@ -177,8 +340,44 @@ mod tests {
fn record_to_str_and_parse_equals_input() { fn record_to_str_and_parse_equals_input() {
assert!(validate_record_parsing(Record::A)); assert!(validate_record_parsing(Record::A));
assert!(validate_record_parsing(Record::AAAA)); assert!(validate_record_parsing(Record::AAAA));
assert!(validate_record_parsing(Record::AFSDB));
assert!(validate_record_parsing(Record::APL));
assert!(validate_record_parsing(Record::CAA));
assert!(validate_record_parsing(Record::CDNSKEY));
assert!(validate_record_parsing(Record::CDS));
assert!(validate_record_parsing(Record::CERT));
assert!(validate_record_parsing(Record::CNAME));
assert!(validate_record_parsing(Record::DHCID));
assert!(validate_record_parsing(Record::DLV));
assert!(validate_record_parsing(Record::DNAME));
assert!(validate_record_parsing(Record::DNSKEY));
assert!(validate_record_parsing(Record::DS));
assert!(validate_record_parsing(Record::HIP));
assert!(validate_record_parsing(Record::IPSECKEY));
assert!(validate_record_parsing(Record::KEY));
assert!(validate_record_parsing(Record::KX));
assert!(validate_record_parsing(Record::LOC));
assert!(validate_record_parsing(Record::MX));
assert!(validate_record_parsing(Record::NAPTR));
assert!(validate_record_parsing(Record::NS));
assert!(validate_record_parsing(Record::NSEC));
assert!(validate_record_parsing(Record::NSEC3));
assert!(validate_record_parsing(Record::NSEC3PARAM));
assert!(validate_record_parsing(Record::OPENPGPKEY));
assert!(validate_record_parsing(Record::PTR)); assert!(validate_record_parsing(Record::PTR));
assert!(validate_record_parsing(Record::RRSIG));
assert!(validate_record_parsing(Record::RP));
assert!(validate_record_parsing(Record::SIG));
assert!(validate_record_parsing(Record::SOA));
assert!(validate_record_parsing(Record::SRV));
assert!(validate_record_parsing(Record::SSHFP));
assert!(validate_record_parsing(Record::TA));
assert!(validate_record_parsing(Record::TKEY));
assert!(validate_record_parsing(Record::TLSA));
assert!(validate_record_parsing(Record::TSIG));
assert!(validate_record_parsing(Record::TXT)); assert!(validate_record_parsing(Record::TXT));
assert!(validate_record_parsing(Record::URI));
assert!(validate_record_parsing(Record::ALIAS));
} }
fn validate_record_parsing(record: Record) -> bool { fn validate_record_parsing(record: Record) -> bool {