forked from 1b-agent/opencadstudio-upstream
fix(doc-api): preserve XDATA and XRecord integrity
This commit is contained in:
1 parent
acba9f87bd
commit
4de2792798
9 files changed
+367
-108
No files matched your search
@@ -21,6 +21,88 @@ fn check(valid: bool, op: &'static str) -> ApiResult<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_payload(valid: bool, op: &'static str, reason: &'static str) -> ApiResult<()> {
|
||||
if valid {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ApiError::validation(op, reason))
|
||||
}
|
||||
}
|
||||
|
||||
fn valid_application_name(name: &str) -> bool {
|
||||
!name.trim().is_empty() && !name.contains('\0')
|
||||
}
|
||||
|
||||
fn valid_xdata_record(app: &str, record: Option<&XDataRecord>) -> bool {
|
||||
valid_application_name(app)
|
||||
&& record.is_none_or(|record| {
|
||||
record.application_name == app
|
||||
&& record.values.iter().all(|value| match value {
|
||||
XDataValue::String(value)
|
||||
| XDataValue::ControlString(value)
|
||||
| XDataValue::LayerName(value) => !value.contains('\0'),
|
||||
XDataValue::Point3D(value)
|
||||
| XDataValue::Position3D(value)
|
||||
| XDataValue::Displacement3D(value)
|
||||
| XDataValue::Direction3D(value) => finite(value),
|
||||
XDataValue::Real(value)
|
||||
| XDataValue::Distance(value)
|
||||
| XDataValue::ScaleFactor(value) => value.is_finite(),
|
||||
XDataValue::BinaryData(_)
|
||||
| XDataValue::Handle(_)
|
||||
| XDataValue::Integer16(_)
|
||||
| XDataValue::Integer32(_) => true,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn valid_xrecord(spec: &XRecordSpec) -> bool {
|
||||
!spec.name.trim().is_empty()
|
||||
&& !spec.name.contains('\0')
|
||||
&& spec.entries.len() <= BULK_ITEM_CAP
|
||||
&& spec.entries.iter().all(|entry| {
|
||||
let code = entry.code;
|
||||
match &entry.value {
|
||||
XRecordValue::String(value) => {
|
||||
matches!(
|
||||
code,
|
||||
0..=4
|
||||
| 6..=9
|
||||
| 100..=102
|
||||
| 300..=309
|
||||
| 410..=419
|
||||
| 430..=439
|
||||
| 470..=479
|
||||
| 999
|
||||
| 1000..=1003
|
||||
) && !value.contains('\0')
|
||||
&& value.encode_utf16().count() <= u16::MAX as usize
|
||||
}
|
||||
XRecordValue::Point3D(value) => {
|
||||
matches!(code, 10..=37 | 110..=139 | 210..=269 | 1010..=1039 | 1043..=1069)
|
||||
&& finite(value)
|
||||
}
|
||||
XRecordValue::Double(value) => {
|
||||
matches!(code, 38..=59 | 140..=149 | 460..=469 | 1040..=1042)
|
||||
&& value.is_finite()
|
||||
}
|
||||
XRecordValue::Int16(_) => {
|
||||
matches!(code, 60..=79 | 170..=179 | 270..=279 | 370..=389 | 400..=409 | 1070)
|
||||
}
|
||||
XRecordValue::Int32(_) => matches!(code, 80..=99 | 420..=429 | 440..=459 | 1071),
|
||||
XRecordValue::Int64(_) => matches!(code, 150..=169),
|
||||
XRecordValue::Byte(_) => matches!(code, 280..=289),
|
||||
XRecordValue::Bool(_) => matches!(code, 290..=299),
|
||||
XRecordValue::Handle(_) => {
|
||||
code < 0 || matches!(code, 5 | 105 | 320..=369 | 390..=399 | 480..=481 | 1005)
|
||||
}
|
||||
XRecordValue::Chunk(value) => {
|
||||
matches!(code, 310..=319 | 1004) && value.len() <= u8::MAX as usize
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn curve(spec: &Curve2Spec) -> ApiResult<()> {
|
||||
use Curve2Spec::*;
|
||||
let valid = match spec {
|
||||
@@ -116,11 +198,36 @@ pub(crate) fn operation(op: &Operation) -> ApiResult<()> {
|
||||
}
|
||||
CreateText(s) => finite(&s.insertion_point) && positive(s.height) && s.rotation.is_finite(),
|
||||
CreateMText(s) => finite(&s.insertion_point) && positive(s.height),
|
||||
SetXDataMany(records) => records.iter().all(|(id, app, record)| {
|
||||
let app_ok = !app.is_empty();
|
||||
let record_ok = record.as_ref().map_or(true, |r| !r.application_name.is_empty() && !r.application_name.contains('\0'));
|
||||
*id != ObjectId::NULL && app_ok && record_ok
|
||||
}),
|
||||
SetXData {
|
||||
id,
|
||||
application_name,
|
||||
record,
|
||||
} => {
|
||||
return check_payload(
|
||||
*id != ObjectId::NULL && valid_xdata_record(application_name, record.as_ref()),
|
||||
"SetXData",
|
||||
"invalid XDATA record",
|
||||
)
|
||||
}
|
||||
SetXDataMany(records) => {
|
||||
return check_payload(
|
||||
records.iter().all(|(id, app, record)| {
|
||||
*id != ObjectId::NULL && valid_xdata_record(app, record.as_ref())
|
||||
}),
|
||||
"SetXDataMany",
|
||||
"invalid XDATA record",
|
||||
)
|
||||
}
|
||||
CreateXRecord(spec) => {
|
||||
return check_payload(valid_xrecord(spec), "CreateXRecord", "invalid XRecord payload")
|
||||
}
|
||||
SetXRecord { id, spec } => {
|
||||
return check_payload(
|
||||
*id != ObjectId::NULL && valid_xrecord(spec),
|
||||
"SetXRecord",
|
||||
"invalid XRecord payload",
|
||||
)
|
||||
}
|
||||
CreateHatch(s) => {
|
||||
(3..=BULK_ITEM_CAP).contains(&s.boundary.len()) && s.boundary.iter().all(|p| finite(p))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user