Skip to content

Commit

Permalink
Merge pull request #186 from anweiss/tdate-tag-validation
Browse files Browse the repository at this point in the history
Fix tdate and time tag validation issues
  • Loading branch information
anweiss authored Apr 10, 2023
2 parents 421f7d6 + bce7b6e commit f32c132
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 32 deletions.
13 changes: 1 addition & 12 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ impl<'a> fmt::Display for GenericParams<'a> {
/// genericarg = "<" S type1 S *("," S type1 S ) ">"
/// ```
#[cfg_attr(target_arch = "wasm32", derive(Serialize))]
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct GenericArgs<'a> {
/// Generic arguments
pub args: Vec<GenericArg<'a>>,
Expand All @@ -646,17 +646,6 @@ pub struct GenericArgs<'a> {
pub span: Span,
}

impl<'a> GenericArgs<'a> {
/// Default `GenericArg`
pub fn default() -> Self {
GenericArgs {
args: Vec::new(),
#[cfg(feature = "ast-span")]
span: (0, 0, 0),
}
}
}

/// Generic argument
#[cfg_attr(target_arch = "wasm32", derive(Serialize))]
#[derive(Debug, Clone, PartialEq)]
Expand Down
12 changes: 6 additions & 6 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ impl<'a> Parser<'a> {
let begin_rule_col = self.lexer_position.column;

let ident = match &self.cur_token {
Token::IDENT(i, s) => self.identifier_from_ident_token(*i, *s),
Token::IDENT(i, s) => self.identifier_from_ident_token(i, *s),
_ => {
#[cfg(feature = "ast-span")]
{
Expand Down Expand Up @@ -940,7 +940,7 @@ impl<'a> Parser<'a> {

match &self.cur_token {
Token::IDENT(ident, socket) => {
let param = self.identifier_from_ident_token(*ident, *socket);
let param = self.identifier_from_ident_token(ident, *socket);

self.next_token()?;

Expand Down Expand Up @@ -1397,7 +1397,7 @@ impl<'a> Parser<'a> {

// optional genericarg detected
if self.peek_token_is(&Token::LANGLEBRACKET) {
let ident = self.identifier_from_ident_token(*ident, *socket);
let ident = self.identifier_from_ident_token(ident, *socket);
let ga = self.parse_genericargs()?;

#[cfg(feature = "ast-span")]
Expand All @@ -1418,7 +1418,7 @@ impl<'a> Parser<'a> {
}

Ok(Type2::Typename {
ident: self.identifier_from_ident_token(*ident, *socket),
ident: self.identifier_from_ident_token(ident, *socket),
generic_args: None,
#[cfg(feature = "ast-span")]
span: (
Expand Down Expand Up @@ -1598,7 +1598,7 @@ impl<'a> Parser<'a> {
let ident = if let Some(ident) = self.cur_token.in_standard_prelude() {
Some(self.identifier_from_ident_token(ident, None))
} else if let Token::IDENT(ident, socket) = &self.cur_token {
Some(self.identifier_from_ident_token(*ident, *socket))
Some(self.identifier_from_ident_token(ident, *socket))
} else {
None
};
Expand Down Expand Up @@ -1684,7 +1684,7 @@ impl<'a> Parser<'a> {
})
}
Token::IDENT(ident, socket) => {
let ident = self.identifier_from_ident_token(*ident, *socket);
let ident = self.identifier_from_ident_token(ident, *socket);
if self.peek_token_is(&Token::LANGLEBRACKET) {
self.next_token()?;

Expand Down
82 changes: 78 additions & 4 deletions src/validator/cbor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
visitor::{self, *},
};

use core::convert::TryInto;
use std::{
borrow::Cow,
collections::HashMap,
Expand Down Expand Up @@ -2292,6 +2293,53 @@ where

Ok(())
}
Value::Tag(tag, value) => {
match *tag {
0 => {
if is_ident_tdate_data_type(self.cddl, ident) {
if let Value::Text(value) = value.as_ref() {
if let Err(e) = chrono::DateTime::parse_from_rfc3339(value) {
self.add_error(format!("expected tdate data type, decoding error: {}", e));
}
} else {
self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
}
} else {
self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
}
}
1 => {
if is_ident_time_data_type(self.cddl, ident) {
if let Value::Integer(value) = *value.as_ref() {
let dt = Utc.timestamp_opt(value.try_into().unwrap(), 0);
if let chrono::LocalResult::None = dt {
self.add_error(format!(
"expected time data type, invalid UNIX timestamp {:?}",
self.cbor
));
}
} else if let Value::Float(value) = value.as_ref() {
let seconds = value.trunc() as i64;
let nanoseconds = (value.fract() * 1e9) as u32;
let dt = Utc.timestamp_opt(seconds, nanoseconds);
if let chrono::LocalResult::None = dt {
self.add_error(format!(
"expected time data type, invalid UNIX timestamp {:?}",
self.cbor
));
}
} else {
self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
}
} else {
self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
}
}
_ => (),
}

Ok(())
}
Value::Array(_) => self.validate_array_items(&ArrayItemToken::Identifier(ident)),
Value::Map(m) => {
match &self.occurrence {
Expand Down Expand Up @@ -3209,10 +3257,10 @@ where
{
None
}
Some(ControlOperator::LT) if *f < *v as f64 => None,
Some(ControlOperator::LE) if *f <= *v as f64 => None,
Some(ControlOperator::GT) if *f > *v as f64 => None,
Some(ControlOperator::GE) if *f >= *v as f64 => None,
Some(ControlOperator::LT) if *f < *v => None,
Some(ControlOperator::LE) if *f <= *v => None,
Some(ControlOperator::GT) if *f > *v => None,
Some(ControlOperator::GE) if *f >= *v => None,
#[cfg(feature = "additional-controls")]
Some(ControlOperator::PLUS) => {
if (*f - *v).abs() < std::f64::EPSILON {
Expand Down Expand Up @@ -3635,4 +3683,30 @@ mod tests {

Ok(())
}

#[test]
fn validate_tdate_tag() -> std::result::Result<(), Box<dyn std::error::Error>> {
let cddl = indoc!(
r#"
root = time
"#
);

let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
if let Err(e) = &cddl {
println!("{}", e);
}

let cbor = ciborium::value::Value::Tag(
1,
Box::from(ciborium::value::Value::Float(1680965875.01_f64)),
);

let cddl = cddl.unwrap();

let mut cv = CBORValidator::new(&cddl, cbor, None);
cv.validate()?;

Ok(())
}
}
8 changes: 4 additions & 4 deletions src/validator/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pub fn cat_operation<'a>(

literals.push(
ByteValue::B64(
base64::encode_config(&concat, base64::URL_SAFE)
base64::encode_config(concat, base64::URL_SAFE)
.into_bytes()
.into(),
)
Expand Down Expand Up @@ -474,7 +474,7 @@ pub fn cat_operation<'a>(

literals.push(
ByteValue::B64(
base64::encode_config(&concat, base64::URL_SAFE)
base64::encode_config(concat, base64::URL_SAFE)
.into_bytes()
.into(),
)
Expand All @@ -500,7 +500,7 @@ pub fn cat_operation<'a>(
};
literals.push(
ByteValue::B64(
base64::encode_config(&concat, base64::URL_SAFE)
base64::encode_config(concat, base64::URL_SAFE)
.into_bytes()
.into(),
)
Expand Down Expand Up @@ -528,7 +528,7 @@ pub fn cat_operation<'a>(
};
literals.push(
ByteValue::B64(
base64::encode_config(&concat, base64::URL_SAFE)
base64::encode_config(concat, base64::URL_SAFE)
.into_bytes()
.into(),
)
Expand Down
12 changes: 6 additions & 6 deletions src/validator/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1040,12 +1040,12 @@ impl<'a, 'b> Visitor<'a, 'b, Error> for JSONValidator<'a> {
Value::Number(n) => {
if let Some(f) = n.as_f64() {
if is_inclusive {
if f < *l as f64 || f > *u as f64 {
if f < *l || f > *u {
self.add_error(error_str);
} else {
return Ok(());
}
} else if f <= *l as f64 || f >= *u as f64 {
} else if f <= *l || f >= *u {
self.add_error(error_str);
return Ok(());
} else {
Expand Down Expand Up @@ -2383,10 +2383,10 @@ impl<'a, 'b> Visitor<'a, 'b, Error> for JSONValidator<'a> {
{
None
}
Some(ControlOperator::LT) if f < *v as f64 => None,
Some(ControlOperator::LE) if f <= *v as f64 => None,
Some(ControlOperator::GT) if f > *v as f64 => None,
Some(ControlOperator::GE) if f >= *v as f64 => None,
Some(ControlOperator::LT) if f < *v => None,
Some(ControlOperator::LE) if f <= *v => None,
Some(ControlOperator::GT) if f > *v => None,
Some(ControlOperator::GE) if f >= *v => None,
#[cfg(feature = "additional-controls")]
Some(ControlOperator::PLUS) => {
if (f - *v).abs() < std::f64::EPSILON {
Expand Down

0 comments on commit f32c132

Please sign in to comment.