Skip to content

Commit 0750dbe

Browse files
authored
Detect invalid wildcards in the language processor (#321)
1 parent 2c41a6c commit 0750dbe

File tree

3 files changed

+88
-12
lines changed

3 files changed

+88
-12
lines changed

src/lang/error.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ pub enum ProcessorError {
6060
Internal(String),
6161
#[error("Middleware error: {0}")]
6262
Middleware(middleware::Error),
63-
#[error("Undefined wildcard: '?{name}' at {span:?}")]
63+
#[error("Undefined wildcard: '?{name}' in predicate '{pred_name}' at {span:?}")]
6464
UndefinedWildcard {
6565
name: String,
66+
pred_name: String,
6667
span: Option<(usize, usize)>,
6768
},
6869
#[error("Invalid literal format for {kind}: '{value}' at {span:?}")]

src/lang/mod.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ mod tests {
3131
middleware::{
3232
hash_str, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Key,
3333
NativePredicate, Params, PodId, PodType, Predicate, RawValue, StatementTmpl,
34-
StatementTmplArg, Value, Wildcard, SELF_ID_HASH,
34+
StatementTmplArg, Value, Wildcard, KEY_SIGNER, KEY_TYPE, SELF_ID_HASH,
3535
},
3636
};
3737

@@ -954,4 +954,43 @@ mod tests {
954954
e => panic!("Expected LangError::Processor, but got {:?}", e),
955955
}
956956
}
957+
958+
#[test]
959+
fn test_e2e_undefined_wildcard() {
960+
let params = Params::default();
961+
let available_batches = &[];
962+
963+
let input = format!(
964+
r#"
965+
identity_verified(username, private: identity_pod) = AND(
966+
Equal(?identity_pod["{key_type}"], {signed_pod_type})
967+
Equal(?identity_pod["{key_signer}"], {identity_server_pk})
968+
Equal(?identity_pod["username"], ?username)
969+
Equal(?identity_pod["user_public_key"], ?user_public_key)
970+
)
971+
"#,
972+
key_type = KEY_TYPE,
973+
signed_pod_type = PodType::Signed as u32,
974+
key_signer = KEY_SIGNER,
975+
identity_server_pk =
976+
"0x0000000000000000000000000000000000000000000000000000000000000000"
977+
);
978+
979+
let result = parse(&input, &params, available_batches);
980+
981+
assert!(result.is_err());
982+
983+
match result.err().unwrap() {
984+
LangError::Processor(e) => match *e {
985+
ProcessorError::UndefinedWildcard {
986+
name, pred_name, ..
987+
} => {
988+
assert_eq!(name, "user_public_key");
989+
assert_eq!(pred_name, "identity_verified");
990+
}
991+
_ => panic!("Expected UndefinedWildcard error, but got {:?}", e),
992+
},
993+
e => panic!("Expected LangError::Processor, but got {:?}", e),
994+
}
995+
}
957996
}

src/lang/processor.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,10 @@ fn process_use_statement(
259259
}
260260

261261
enum StatementContext<'a> {
262-
CustomPredicate,
262+
CustomPredicate {
263+
pred_name: &'a str,
264+
argument_names: &'a HashSet<String>,
265+
},
263266
Request {
264267
custom_batch: &'a Arc<CustomPredicateBatch>,
265268
wildcard_names: &'a mut Vec<String>,
@@ -295,21 +298,49 @@ fn second_pass(
295298
fn pest_pair_to_builder_arg(
296299
params: &Params,
297300
arg_content_pair: &Pair<Rule>,
301+
context: &StatementContext,
298302
) -> Result<BuilderArg, ProcessorError> {
299303
match arg_content_pair.as_rule() {
300304
Rule::literal_value => {
301305
let value = process_literal_value(params, arg_content_pair)?;
302306
Ok(BuilderArg::Literal(value))
303307
}
304308
Rule::wildcard => {
305-
let name = arg_content_pair.as_str().strip_prefix("?").unwrap();
306-
Ok(BuilderArg::WildcardLiteral(name.to_string()))
309+
let wc_str = arg_content_pair.as_str().strip_prefix("?").unwrap();
310+
if let StatementContext::CustomPredicate {
311+
argument_names,
312+
pred_name,
313+
} = context
314+
{
315+
if !argument_names.contains(wc_str) {
316+
return Err(ProcessorError::UndefinedWildcard {
317+
name: wc_str.to_string(),
318+
pred_name: pred_name.to_string(),
319+
span: Some(get_span(arg_content_pair)),
320+
});
321+
}
322+
}
323+
Ok(BuilderArg::WildcardLiteral(wc_str.to_string()))
307324
}
308325
Rule::anchored_key => {
309326
let mut inner_ak_pairs = arg_content_pair.clone().into_inner();
310327
let pod_id_pair = inner_ak_pairs.next().unwrap();
311328
let pod_id_wc_str = pod_id_pair.as_str().strip_prefix("?").unwrap();
312329

330+
if let StatementContext::CustomPredicate {
331+
argument_names,
332+
pred_name,
333+
} = context
334+
{
335+
if !argument_names.contains(pod_id_wc_str) {
336+
return Err(ProcessorError::UndefinedWildcard {
337+
name: pod_id_wc_str.to_string(),
338+
pred_name: pred_name.to_string(),
339+
span: Some(get_span(arg_content_pair)),
340+
});
341+
}
342+
}
343+
313344
let key_part_pair = inner_ak_pairs.next().unwrap();
314345
let key_str = parse_pest_string_literal(&key_part_pair)?;
315346
Ok(BuilderArg::Key(pod_id_wc_str.to_string(), key_str))
@@ -516,7 +547,10 @@ fn process_and_add_custom_predicate_to_batch(
516547
params,
517548
&stmt_pair,
518549
processing_ctx,
519-
StatementContext::CustomPredicate,
550+
&mut StatementContext::CustomPredicate {
551+
pred_name: &name,
552+
argument_names: &defined_arg_names,
553+
},
520554
)?;
521555
statement_builders.push(stb);
522556
}
@@ -557,7 +591,7 @@ fn process_request_def(
557591
params,
558592
&stmt_pair,
559593
processing_ctx,
560-
StatementContext::Request {
594+
&mut StatementContext::Request {
561595
custom_batch,
562596
wildcard_names: &mut request_wildcard_names,
563597
defined_wildcards: &mut defined_request_wildcards,
@@ -582,21 +616,21 @@ fn process_statement_template(
582616
params: &Params,
583617
stmt_pair: &Pair<Rule>,
584618
processing_ctx: &ProcessingContext,
585-
mut context: StatementContext,
619+
context: &mut StatementContext,
586620
) -> Result<StatementTmplBuilder, ProcessorError> {
587621
let mut inner_stmt_pairs = stmt_pair.clone().into_inner();
588622
let name_pair = inner_stmt_pairs
589623
.find(|p| p.as_rule() == Rule::identifier)
590624
.unwrap();
591625
let stmt_name_str = name_pair.as_str();
592626

593-
let builder_args = parse_statement_args(params, stmt_pair)?;
627+
let builder_args = parse_statement_args(params, stmt_pair, context)?;
594628

595629
if let StatementContext::Request {
596630
wildcard_names,
597631
defined_wildcards,
598632
..
599-
} = &mut context
633+
} = context
600634
{
601635
let mut temp_stmt_wildcard_names: Vec<String> = Vec::new();
602636
for arg in &builder_args {
@@ -626,7 +660,7 @@ fn process_statement_template(
626660
.get(stmt_name_str)
627661
{
628662
match context {
629-
StatementContext::CustomPredicate => Predicate::BatchSelf(*pred_index),
663+
StatementContext::CustomPredicate { .. } => Predicate::BatchSelf(*pred_index),
630664
StatementContext::Request { custom_batch, .. } => {
631665
let custom_pred_ref = CustomPredicateRef::new(custom_batch.clone(), *pred_index);
632666
Predicate::Custom(custom_pred_ref)
@@ -861,6 +895,7 @@ fn resolve_wildcard(
861895
.map(|index| Wildcard::new(name_to_resolve.to_string(), index))
862896
.ok_or_else(|| ProcessorError::UndefinedWildcard {
863897
name: name_to_resolve.to_string(),
898+
pred_name: "REQUEST".to_string(),
864899
span: None,
865900
})
866901
}
@@ -906,6 +941,7 @@ fn resolve_request_statement_builder(
906941
fn parse_statement_args(
907942
params: &Params,
908943
stmt_pair: &Pair<Rule>,
944+
context: &StatementContext,
909945
) -> Result<Vec<BuilderArg>, ProcessorError> {
910946
let mut builder_args = Vec::new();
911947
let mut inner_stmt_pairs = stmt_pair.clone().into_inner();
@@ -917,7 +953,7 @@ fn parse_statement_args(
917953
.filter(|p| p.as_rule() == Rule::statement_arg)
918954
{
919955
let arg_content_pair = arg_pair.into_inner().next().unwrap();
920-
let builder_arg = pest_pair_to_builder_arg(params, &arg_content_pair)?;
956+
let builder_arg = pest_pair_to_builder_arg(params, &arg_content_pair, context)?;
921957
builder_args.push(builder_arg);
922958
}
923959
}

0 commit comments

Comments
 (0)