use crate::ArnError;
pub fn validate_partition(partition: &str) -> Result<(), ArnError> {
if partition.is_empty() {
return Err(ArnError::InvalidPartition(partition.to_string()));
}
let mut last_was_dash = true;
for (i, c) in partition.char_indices() {
if i == 32 {
return Err(ArnError::InvalidPartition(partition.to_string()));
}
if (c.is_alphabetic() && !c.is_uppercase()) || c.is_ascii_digit() {
last_was_dash = false;
} else if c == '-' {
if last_was_dash {
return Err(ArnError::InvalidPartition(partition.to_string()));
}
last_was_dash = true;
} else {
return Err(ArnError::InvalidPartition(partition.to_string()));
}
}
if last_was_dash {
Err(ArnError::InvalidPartition(partition.to_string()))
} else {
Ok(())
}
}
pub fn validate_account_id(account_id: &str) -> Result<(), ArnError> {
if account_id != "aws" {
let a_bytes = account_id.as_bytes();
if a_bytes.len() != 12 {
return Err(ArnError::InvalidAccountId(account_id.to_string()));
}
for c in a_bytes.iter() {
if !c.is_ascii_digit() {
return Err(ArnError::InvalidAccountId(account_id.to_string()));
}
}
}
Ok(())
}
#[derive(PartialEq)]
enum RegionParseState {
Start,
LastWasAlpha,
LastWasDash,
LastWasDigit,
}
enum RegionParseSection {
Region,
LocalRegion,
}
pub fn validate_region(region: &str) -> Result<(), ArnError> {
if region == "local" {
return Ok(());
}
let mut section = RegionParseSection::Region;
let mut state = RegionParseState::Start;
for c in region.chars() {
if c == '-' {
match state {
RegionParseState::Start | RegionParseState::LastWasDash => {
return Err(ArnError::InvalidRegion(region.to_string()));
}
RegionParseState::LastWasAlpha => {
state = RegionParseState::LastWasDash;
}
RegionParseState::LastWasDigit => match section {
RegionParseSection::Region => {
section = RegionParseSection::LocalRegion;
state = RegionParseState::LastWasDash;
}
RegionParseSection::LocalRegion => {
return Err(ArnError::InvalidRegion(region.to_string()));
}
},
}
} else if c.is_alphabetic() && !c.is_uppercase() {
match state {
RegionParseState::Start | RegionParseState::LastWasDash | RegionParseState::LastWasAlpha => {
state = RegionParseState::LastWasAlpha;
}
_ => {
return Err(ArnError::InvalidRegion(region.to_string()));
}
}
} else if c.is_ascii_digit() {
match state {
RegionParseState::LastWasDash | RegionParseState::LastWasDigit => {
state = RegionParseState::LastWasDigit;
}
_ => {
return Err(ArnError::InvalidRegion(region.to_string()));
}
}
} else {
return Err(ArnError::InvalidRegion(region.to_string()));
}
}
if state == RegionParseState::LastWasDigit {
Ok(())
} else {
Err(ArnError::InvalidRegion(region.to_string()))
}
}
pub fn validate_service(service: &str) -> Result<(), ArnError> {
if service.is_empty() {
return Err(ArnError::InvalidService(service.to_string()));
}
let mut last_was_dash = true;
for c in service.chars() {
if c.is_alphanumeric() && !c.is_uppercase() {
last_was_dash = false;
} else if c == '-' {
if last_was_dash {
return Err(ArnError::InvalidService(service.to_string()));
}
last_was_dash = true;
} else {
return Err(ArnError::InvalidService(service.to_string()));
}
}
if last_was_dash {
Err(ArnError::InvalidService(service.to_string()))
} else {
Ok(())
}
}
#[cfg(test)]
mod test {
#[test]
fn check_valid_services() {
assert!(super::validate_service("s3").is_ok());
assert!(super::validate_service("kafka-cluster").is_ok());
assert!(super::validate_service("execute-api").is_ok());
}
}