use openssl::{rsa::Rsa, pkey::Public};
use serde_json::Value;
use crate::strings::ERROR_SERDE_PARSE;
struct StaticJsonStrings {
pub name: &'static str,
pub update_path_prefix: &'static str,
pub scope: &'static str,
pub replaces_default_rulesets: &'static str,
pub pem: &'static str,
}
const JSON_STRINGS: StaticJsonStrings = StaticJsonStrings {
name: "name",
update_path_prefix: "update_path_prefix",
scope: "scope",
replaces_default_rulesets: "replaces_default_rulesets",
pem: "pem",
};
#[derive(Debug)]
pub struct UpdateChannel {
pub name: String,
pub key: Rsa<Public>,
pub update_path_prefix: String,
pub scope: Option<String>,
pub replaces_default_rulesets: bool,
}
impl From<&String> for UpdateChannel {
fn from(json_string: &String) -> UpdateChannel {
let update_channel: Value = serde_json::from_str(&json_string).expect(ERROR_SERDE_PARSE);
UpdateChannel::from(&update_channel)
}
}
impl From<&Value> for UpdateChannel {
fn from(json_value: &Value) -> UpdateChannel {
if let Value::Object(update_channel) = json_value {
let name = match update_channel.get(JSON_STRINGS.name) {
Some(Value::String(name)) => name.to_string(),
_ => panic!("Name can not be blank")
};
let update_path_prefix = match update_channel.get(JSON_STRINGS.update_path_prefix) {
Some(Value::String(update_path_prefix)) => update_path_prefix.to_string(),
_ => panic!("Update path prefix can not be blank")
};
let scope = match update_channel.get(JSON_STRINGS.scope) {
Some(Value::String(scope)) if scope == "" => None,
Some(Value::String(scope)) => Some(scope.to_string()),
_ => None
};
let replaces_default_rulesets = match update_channel.get(JSON_STRINGS.replaces_default_rulesets) {
Some(Value::Bool(replaces_default_rulesets)) => replaces_default_rulesets.clone(),
_ => false
};
let key = match update_channel.get(JSON_STRINGS.pem) {
Some(Value::String(pem)) => {
match Rsa::public_key_from_pem(&pem.clone().into_bytes()) {
Ok(key) => key,
_ => panic!("Could not parse public key")
}
},
_ => panic!("Pem can not be blank")
};
UpdateChannel {
name,
key,
update_path_prefix,
scope,
replaces_default_rulesets,
}
} else {
panic!("Unexpected: update channel is not an object");
}
}
}
#[derive(Debug)]
pub struct UpdateChannels(Vec<UpdateChannel>);
impl UpdateChannels {
pub fn get_all(&self) -> &Vec<UpdateChannel>{
&self.0
}
pub fn get_all_mut(&mut self) -> &mut Vec<UpdateChannel>{
&mut self.0
}
}
impl From<&String> for UpdateChannels {
fn from(json_string: &String) -> UpdateChannels {
if let Value::Array(update_channels) = serde_json::from_str(&json_string).expect(ERROR_SERDE_PARSE) {
UpdateChannels(update_channels.into_iter().map(|uc| {
UpdateChannel::from(&uc)
}).collect())
} else {
panic!("Unexpected: update channels is not an array")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
fn mock_update_channels_json() -> String {
fs::read_to_string("tests/update_channels.json").unwrap()
}
fn create_mock_update_channels() -> UpdateChannels {
UpdateChannels::from(&mock_update_channels_json())
}
#[test]
fn creates_update_channels_correctly() {
let ucs = create_mock_update_channels();
let update_channels_representation = fs::read_to_string("tests/update_channels_representation.txt").unwrap();
assert_eq!(format!("{:?}", ucs), update_channels_representation);
}
#[test]
#[should_panic]
fn panics_if_no_name_specified() {
let mut update_channels: Value = serde_json::from_str(&mock_update_channels_json()).expect(ERROR_SERDE_PARSE);
update_channels.get_mut(0).unwrap().get_mut(JSON_STRINGS.name).unwrap().take();
UpdateChannel::from(update_channels.get(0).unwrap());
}
#[test]
#[should_panic]
fn panics_if_no_update_path_prefix_specified() {
let mut update_channels: Value = serde_json::from_str(&mock_update_channels_json()).expect(ERROR_SERDE_PARSE);
update_channels.get_mut(0).unwrap().get_mut(JSON_STRINGS.update_path_prefix).unwrap().take();
UpdateChannel::from(update_channels.get(0).unwrap());
}
#[test]
#[should_panic]
fn panics_if_no_pem_specified() {
let mut update_channels: Value = serde_json::from_str(&mock_update_channels_json()).expect(ERROR_SERDE_PARSE);
update_channels.get_mut(0).unwrap().get_mut(JSON_STRINGS.pem).unwrap().take();
UpdateChannel::from(update_channels.get(0).unwrap());
}
#[test]
#[should_panic]
fn panics_if_pem_specified_incorrectly() {
let mut update_channels: Value = serde_json::from_str(&mock_update_channels_json()).expect(ERROR_SERDE_PARSE);
let pem = update_channels.get_mut(0).unwrap().get_mut(JSON_STRINGS.pem).unwrap();
*pem = Value::String(String::from("Not a pem value"));
UpdateChannel::from(update_channels.get(0).unwrap());
}
}