1use super::{
6 constrained_rule, date, fact, pred, rule, string, var, Binary, Block, Check, CheckKind,
7 Convert, Expression, Fact, Op, Rule, Scope, Term,
8};
9use crate::builder_ext::BuilderExt;
10use crate::crypto::PublicKey;
11use crate::datalog::{get_schema_version, SymbolTable};
12use crate::error;
13use biscuit_parser::parser::parse_block_source;
14
15use std::time::SystemTime;
16use std::{collections::HashMap, convert::TryInto, fmt};
17
18#[derive(Clone, Debug, Default)]
20pub struct BlockBuilder {
21 pub facts: Vec<Fact>,
22 pub rules: Vec<Rule>,
23 pub checks: Vec<Check>,
24 pub scopes: Vec<Scope>,
25 pub context: Option<String>,
26}
27
28impl BlockBuilder {
29 pub fn new() -> BlockBuilder {
30 BlockBuilder::default()
31 }
32
33 pub fn merge(mut self, mut other: BlockBuilder) -> Self {
34 self.facts.append(&mut other.facts);
35 self.rules.append(&mut other.rules);
36 self.checks.append(&mut other.checks);
37
38 if let Some(c) = other.context {
39 self.context = Some(c);
40 }
41 self
42 }
43
44 pub fn fact<F: TryInto<Fact>>(mut self, fact: F) -> Result<Self, error::Token>
45 where
46 error::Token: From<<F as TryInto<Fact>>::Error>,
47 {
48 let fact = fact.try_into()?;
49 fact.validate()?;
50
51 self.facts.push(fact);
52 Ok(self)
53 }
54
55 pub fn rule<R: TryInto<Rule>>(mut self, rule: R) -> Result<Self, error::Token>
56 where
57 error::Token: From<<R as TryInto<Rule>>::Error>,
58 {
59 let rule = rule.try_into()?;
60 rule.validate_parameters()?;
61 self.rules.push(rule);
62 Ok(self)
63 }
64
65 pub fn check<C: TryInto<Check>>(mut self, check: C) -> Result<Self, error::Token>
66 where
67 error::Token: From<<C as TryInto<Check>>::Error>,
68 {
69 let check = check.try_into()?;
70 check.validate_parameters()?;
71 self.checks.push(check);
72 Ok(self)
73 }
74
75 pub fn code<T: AsRef<str>>(self, source: T) -> Result<Self, error::Token> {
76 self.code_with_params(source, HashMap::new(), HashMap::new())
77 }
78
79 pub fn code_with_params<T: AsRef<str>>(
82 mut self,
83 source: T,
84 params: HashMap<String, Term>,
85 scope_params: HashMap<String, PublicKey>,
86 ) -> Result<Self, error::Token> {
87 let input = source.as_ref();
88
89 let source_result = parse_block_source(input).map_err(|e| {
90 let e2: biscuit_parser::error::LanguageError = e.into();
91 e2
92 })?;
93
94 for (_, fact) in source_result.facts.into_iter() {
95 let mut fact: Fact = fact.into();
96 for (name, value) in ¶ms {
97 let res = match fact.set(name, value) {
98 Ok(_) => Ok(()),
99 Err(error::Token::Language(
100 biscuit_parser::error::LanguageError::Parameters {
101 missing_parameters, ..
102 },
103 )) if missing_parameters.is_empty() => Ok(()),
104 Err(e) => Err(e),
105 };
106 res?;
107 }
108 fact.validate()?;
109 self.facts.push(fact);
110 }
111
112 for (_, rule) in source_result.rules.into_iter() {
113 let mut rule: Rule = rule.into();
114 for (name, value) in ¶ms {
115 let res = match rule.set(name, value) {
116 Ok(_) => Ok(()),
117 Err(error::Token::Language(
118 biscuit_parser::error::LanguageError::Parameters {
119 missing_parameters, ..
120 },
121 )) if missing_parameters.is_empty() => Ok(()),
122 Err(e) => Err(e),
123 };
124 res?;
125 }
126 for (name, value) in &scope_params {
127 let res = match rule.set_scope(name, *value) {
128 Ok(_) => Ok(()),
129 Err(error::Token::Language(
130 biscuit_parser::error::LanguageError::Parameters {
131 missing_parameters, ..
132 },
133 )) if missing_parameters.is_empty() => Ok(()),
134 Err(e) => Err(e),
135 };
136 res?;
137 }
138 rule.validate_parameters()?;
139 self.rules.push(rule);
140 }
141
142 for (_, check) in source_result.checks.into_iter() {
143 let mut check: Check = check.into();
144 for (name, value) in ¶ms {
145 let res = match check.set(name, value) {
146 Ok(_) => Ok(()),
147 Err(error::Token::Language(
148 biscuit_parser::error::LanguageError::Parameters {
149 missing_parameters, ..
150 },
151 )) if missing_parameters.is_empty() => Ok(()),
152 Err(e) => Err(e),
153 };
154 res?;
155 }
156 for (name, value) in &scope_params {
157 let res = match check.set_scope(name, *value) {
158 Ok(_) => Ok(()),
159 Err(error::Token::Language(
160 biscuit_parser::error::LanguageError::Parameters {
161 missing_parameters, ..
162 },
163 )) if missing_parameters.is_empty() => Ok(()),
164 Err(e) => Err(e),
165 };
166 res?;
167 }
168 check.validate_parameters()?;
169 self.checks.push(check);
170 }
171
172 Ok(self)
173 }
174
175 pub fn scope(mut self, scope: Scope) -> Self {
176 self.scopes.push(scope);
177 self
178 }
179
180 pub fn context(mut self, context: String) -> Self {
181 self.context = Some(context);
182 self
183 }
184
185 pub(crate) fn build(self, mut symbols: SymbolTable) -> Block {
186 let symbols_start = symbols.current_offset();
187 let public_keys_start = symbols.public_keys.current_offset();
188
189 let mut facts = Vec::new();
190 for fact in self.facts {
191 facts.push(fact.convert(&mut symbols));
192 }
193
194 let mut rules = Vec::new();
195 for rule in &self.rules {
196 rules.push(rule.convert(&mut symbols));
197 }
198
199 let mut checks = Vec::new();
200 for check in &self.checks {
201 checks.push(check.convert(&mut symbols));
202 }
203
204 let mut scopes = Vec::new();
205 for scope in &self.scopes {
206 scopes.push(scope.convert(&mut symbols));
207 }
208
209 let new_syms = symbols.split_at(symbols_start);
210 let public_keys = symbols.public_keys.split_at(public_keys_start);
211 let schema_version = get_schema_version(&facts, &rules, &checks, &scopes);
212
213 Block {
214 symbols: new_syms,
215 facts,
216 rules,
217 checks,
218 context: self.context,
219 version: schema_version.version(),
220 external_key: None,
221 public_keys,
222 scopes,
223 }
224 }
225
226 pub(crate) fn convert_from(
227 block: &Block,
228 symbols: &SymbolTable,
229 ) -> Result<Self, error::Format> {
230 Ok(BlockBuilder {
231 facts: block
232 .facts
233 .iter()
234 .map(|f| Fact::convert_from(f, symbols))
235 .collect::<Result<Vec<Fact>, error::Format>>()?,
236 rules: block
237 .rules
238 .iter()
239 .map(|r| Rule::convert_from(r, symbols))
240 .collect::<Result<Vec<Rule>, error::Format>>()?,
241 checks: block
242 .checks
243 .iter()
244 .map(|c| Check::convert_from(c, symbols))
245 .collect::<Result<Vec<Check>, error::Format>>()?,
246 scopes: block
247 .scopes
248 .iter()
249 .map(|s| Scope::convert_from(s, symbols))
250 .collect::<Result<Vec<Scope>, error::Format>>()?,
251 context: block.context.clone(),
252 })
253 }
254
255 #[cfg(test)]
257 pub(crate) fn check_right(self, right: &str) -> Result<Self, error::Token> {
258 use crate::builder::{pred, string, var};
259
260 use super::rule;
261
262 let term = string(right);
263 let check = rule(
264 "check_right",
265 &[string(right)],
266 &[
267 pred("resource", &[var("resource_name")]),
268 pred("operation", &[term]),
269 pred("right", &[var("resource_name"), string(right)]),
270 ],
271 );
272
273 self.check(check)
274 }
275}
276
277impl fmt::Display for BlockBuilder {
278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279 for mut fact in self.facts.clone().into_iter() {
280 fact.apply_parameters();
281 writeln!(f, "{};", &fact)?;
282 }
283 for mut rule in self.rules.clone().into_iter() {
284 rule.apply_parameters();
285 writeln!(f, "{};", &rule)?;
286 }
287 for mut check in self.checks.clone().into_iter() {
288 check.apply_parameters();
289 writeln!(f, "{};", &check)?;
290 }
291 Ok(())
292 }
293}
294
295impl BuilderExt for BlockBuilder {
296 fn resource(mut self, name: &str) -> Self {
297 self.facts.push(fact("resource", &[string(name)]));
298 self
299 }
300 fn check_resource(mut self, name: &str) -> Self {
301 self.checks.push(Check {
302 queries: vec![rule(
303 "resource_check",
304 &[string("resource_check")],
305 &[pred("resource", &[string(name)])],
306 )],
307 kind: CheckKind::One,
308 });
309 self
310 }
311 fn operation(mut self, name: &str) -> Self {
312 self.facts.push(fact("operation", &[string(name)]));
313 self
314 }
315 fn check_operation(mut self, name: &str) -> Self {
316 self.checks.push(Check {
317 queries: vec![rule(
318 "operation_check",
319 &[string("operation_check")],
320 &[pred("operation", &[string(name)])],
321 )],
322 kind: CheckKind::One,
323 });
324 self
325 }
326 fn check_resource_prefix(mut self, prefix: &str) -> Self {
327 let check = constrained_rule(
328 "prefix",
329 &[var("resource")],
330 &[pred("resource", &[var("resource")])],
331 &[Expression {
332 ops: vec![
333 Op::Value(var("resource")),
334 Op::Value(string(prefix)),
335 Op::Binary(Binary::Prefix),
336 ],
337 }],
338 );
339
340 self.checks.push(Check {
341 queries: vec![check],
342 kind: CheckKind::One,
343 });
344 self
345 }
346
347 fn check_resource_suffix(mut self, suffix: &str) -> Self {
348 let check = constrained_rule(
349 "suffix",
350 &[var("resource")],
351 &[pred("resource", &[var("resource")])],
352 &[Expression {
353 ops: vec![
354 Op::Value(var("resource")),
355 Op::Value(string(suffix)),
356 Op::Binary(Binary::Suffix),
357 ],
358 }],
359 );
360
361 self.checks.push(Check {
362 queries: vec![check],
363 kind: CheckKind::One,
364 });
365 self
366 }
367
368 fn check_expiration_date(mut self, exp: SystemTime) -> Self {
369 let empty: Vec<Term> = Vec::new();
370 let ops = vec![
371 Op::Value(var("time")),
372 Op::Value(date(&exp)),
373 Op::Binary(Binary::LessOrEqual),
374 ];
375 let check = constrained_rule(
376 "query",
377 &empty,
378 &[pred("time", &[var("time")])],
379 &[Expression { ops }],
380 );
381
382 self.checks.push(Check {
383 queries: vec![check],
384 kind: CheckKind::One,
385 });
386 self
387 }
388}