blindplane_access/
codec.rs1use crate::{ACCESS_FORMAT_VERSION, AccessError};
4
5pub(crate) const MAGIC: &[u8; 4] = b"BPAC";
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct AccessValidationPolicy {
10 pub max_identifier_bytes: usize,
12 pub max_rules: usize,
14 pub max_wrapped_grant_bytes: usize,
16 pub max_event_body_bytes: usize,
18}
19
20impl Default for AccessValidationPolicy {
21 fn default() -> Self {
22 Self {
23 max_identifier_bytes: 255,
24 max_rules: 512,
25 max_wrapped_grant_bytes: 4 * 1024,
26 max_event_body_bytes: 8 * 1024 * 1024,
27 }
28 }
29}
30
31pub(crate) fn push_header(out: &mut Vec<u8>, tag: u8) {
32 out.extend_from_slice(MAGIC);
33 out.extend_from_slice(&ACCESS_FORMAT_VERSION.to_be_bytes());
34 out.push(tag);
35}
36
37pub(crate) fn push_bytes(out: &mut Vec<u8>, bytes: &[u8]) {
38 let length = u32::try_from(bytes.len()).expect("access values are bounded below u32::MAX");
39 out.extend_from_slice(&length.to_be_bytes());
40 out.extend_from_slice(bytes);
41}
42
43pub(crate) fn push_string(out: &mut Vec<u8>, value: &str) {
44 push_bytes(out, value.as_bytes());
45}
46
47pub(crate) struct Cursor<'a> {
48 bytes: &'a [u8],
49 offset: usize,
50}
51
52impl<'a> Cursor<'a> {
53 pub(crate) const fn new(bytes: &'a [u8]) -> Self {
54 Self { bytes, offset: 0 }
55 }
56
57 pub(crate) fn take_header(&mut self, expected_tag: u8) -> Result<(), AccessError> {
58 if self.take_exact(MAGIC.len())? != MAGIC {
59 return Err(AccessError::WrongObjectType);
60 }
61 let version = self.take_u16()?;
62 if version != ACCESS_FORMAT_VERSION {
63 return Err(AccessError::UnsupportedVersion(version));
64 }
65 if self.take_u8()? != expected_tag {
66 return Err(AccessError::WrongObjectType);
67 }
68 Ok(())
69 }
70
71 pub(crate) const fn is_empty(&self) -> bool {
72 self.offset == self.bytes.len()
73 }
74
75 pub(crate) fn take_exact(&mut self, length: usize) -> Result<&'a [u8], AccessError> {
76 let end = self
77 .offset
78 .checked_add(length)
79 .ok_or(AccessError::Truncated)?;
80 if end > self.bytes.len() {
81 return Err(AccessError::Truncated);
82 }
83 let value = &self.bytes[self.offset..end];
84 self.offset = end;
85 Ok(value)
86 }
87
88 pub(crate) fn take_u8(&mut self) -> Result<u8, AccessError> {
89 Ok(self.take_exact(1)?[0])
90 }
91
92 pub(crate) fn take_u16(&mut self) -> Result<u16, AccessError> {
93 Ok(u16::from_be_bytes(
94 self.take_exact(2)?.try_into().expect("two bytes"),
95 ))
96 }
97
98 pub(crate) fn take_u32(&mut self) -> Result<u32, AccessError> {
99 Ok(u32::from_be_bytes(
100 self.take_exact(4)?.try_into().expect("four bytes"),
101 ))
102 }
103
104 pub(crate) fn take_u64(&mut self) -> Result<u64, AccessError> {
105 Ok(u64::from_be_bytes(
106 self.take_exact(8)?.try_into().expect("eight bytes"),
107 ))
108 }
109
110 pub(crate) fn take_array32(&mut self) -> Result<[u8; 32], AccessError> {
111 Ok(self.take_exact(32)?.try_into().expect("32 bytes"))
112 }
113
114 pub(crate) fn take_array64(&mut self) -> Result<[u8; 64], AccessError> {
115 Ok(self.take_exact(64)?.try_into().expect("64 bytes"))
116 }
117
118 pub(crate) fn take_len(&mut self, limit: usize) -> Result<usize, AccessError> {
119 let length = self.take_u32()?;
120 let length = usize::try_from(length).expect("u32 fits into usize on supported targets");
121 if length > limit {
122 return Err(AccessError::LengthLimit(length));
123 }
124 Ok(length)
125 }
126
127 pub(crate) fn take_bytes(&mut self, limit: usize) -> Result<&'a [u8], AccessError> {
128 let length = self.take_len(limit)?;
129 self.take_exact(length)
130 }
131
132 pub(crate) fn take_string(&mut self, limit: usize) -> Result<String, AccessError> {
133 let bytes = self.take_bytes(limit)?;
134 core::str::from_utf8(bytes)
135 .map(str::to_owned)
136 .map_err(|_| AccessError::InvalidUtf8)
137 }
138}
139
140pub(crate) fn validate_identifier(value: &str, limit: usize) -> Result<(), AccessError> {
141 if value.is_empty() || value.len() > limit {
142 Err(AccessError::InvalidIdentifier)
143 } else {
144 Ok(())
145 }
146}