Skip to content

Commit

Permalink
fix(rust/signed_doc): replace ULID with UUIDv7
Browse files Browse the repository at this point in the history
  • Loading branch information
saibatizoku committed Dec 10, 2024
1 parent 424cc0a commit b22a672
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 45 deletions.
3 changes: 1 addition & 2 deletions rust/signed_doc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ jsonschema = "0.18.0"
coset = "0.3.7"
brotli = "7.0.0"
ed25519-dalek = { version = "2.1.1", features = ["pem"] }
uuid = { version = "1.10.0", features = ["v4", "serde"] }
ulid = { version = "1.1.3", features = ["serde"] }
uuid = { version = "1.10.0", features = ["v4", "v7", "serde"] }
17 changes: 8 additions & 9 deletions rust/signed_doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ which **must** be present (most of the fields originally defined by this
(this parameter is used to indicate the content encodings algorithm of the payload data,
in this particular case [brotli] compression data format is used).
* `type`: CBOR encoded UUID.
* `id`: CBOR encoded ULID.
* `ver`: CBOR encoded ULID.
* `ref`: CBOR encoded ULID or two elements array of ULIDs (optional).
* `template`: CBOR encoded ULID or two elements array of ULIDs (optional).
* `reply`: CBOR encoded ULID or two elements array of ULIDs (optional).
* `id`: CBOR encoded UUIDv7.
* `ver`: CBOR encoded UUIDv7.
* `ref`: CBOR encoded UUIDv7 or two elements array of UUIDv7 (optional).
* `template`: CBOR encoded UUIDv7 or two elements array of UUIDv7 (optional).
* `reply`: CBOR encoded UUIDv7 or two elements array of UUIDv7 (optional).
* `section`: CBOR encoded string (optional).
* `collabs`: CBOR encoded array of any CBOR types (optional).

Expand All @@ -46,8 +46,8 @@ protected_header = {
3 => 30, ; "content type": Json
"content encoding" => "br", ; payload content encoding, brotli compression
"type" => UUID,
"id" => ULID,
"ver" => ULID,
"id" => UUIDv7,
"ver" => UUIDv7,
? "ref" => reference_type,
? "template" => reference_type,
? "reply" => reference_type,
Expand All @@ -56,8 +56,7 @@ protected_header = {
}
UUID = #6.37(bytes)
ULID = #6.32780(bytes)
reference_type = ULID / [ULID, ULID] ; either ULID or [ULID, ULID]
reference_type = UUIDv7 / [UUIDv7, UUIDv7] ; either UUIDv7 or [UUIDv7, UUIDv7]
```

### COSE payload
Expand Down
47 changes: 13 additions & 34 deletions rust/signed_doc/examples/mk_signed_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ enum Cli {
const CONTENT_ENCODING_KEY: &str = "content encoding";
const CONTENT_ENCODING_VALUE: &str = "br";
const UUID_CBOR_TAG: u64 = 37;
const ULID_CBOR_TAG: u64 = 32780;

#[derive(Debug, serde::Deserialize)]
struct Metadata {
r#type: uuid::Uuid,
id: ulid::Ulid,
ver: ulid::Ulid,
id: uuid::Uuid,
ver: uuid::Uuid,
r#ref: Option<DocumentRef>,
template: Option<DocumentRef>,
reply: Option<DocumentRef>,
Expand All @@ -76,29 +75,9 @@ struct Metadata {
#[serde(untagged)]
enum DocumentRef {
/// Reference to the latest document
Latest { id: ulid::Ulid },
Latest { id: uuid::Uuid },
/// Reference to the specific document version
WithVer { id: ulid::Ulid, ver: ulid::Ulid },
}

fn encode_cbor_ulid(ulid: &ulid::Ulid) -> coset::cbor::Value {
coset::cbor::Value::Tag(
ULID_CBOR_TAG,
coset::cbor::Value::Bytes(ulid.to_bytes().to_vec()).into(),
)
}

fn decode_cbor_ulid(val: &coset::cbor::Value) -> anyhow::Result<ulid::Ulid> {
let Some((ULID_CBOR_TAG, coset::cbor::Value::Bytes(bytes))) = val.as_tag() else {
anyhow::bail!("Invalid CBOR encoded ULID type");
};
let ulid = ulid::Ulid::from_bytes(
bytes
.clone()
.try_into()
.map_err(|_| anyhow::anyhow!("Invalid CBOR encoded ULID type, invalid bytes size"))?,
);
Ok(ulid)
WithVer { id: uuid::Uuid, ver: uuid::Uuid },
}

fn encode_cbor_uuid(uuid: &uuid::Uuid) -> coset::cbor::Value {
Expand All @@ -123,24 +102,24 @@ fn decode_cbor_uuid(val: &coset::cbor::Value) -> anyhow::Result<uuid::Uuid> {

fn encode_cbor_document_ref(doc_ref: &DocumentRef) -> coset::cbor::Value {
match doc_ref {
DocumentRef::Latest { id } => encode_cbor_ulid(id),
DocumentRef::Latest { id } => encode_cbor_uuid(id),
DocumentRef::WithVer { id, ver } => {
coset::cbor::Value::Array(vec![encode_cbor_ulid(id), encode_cbor_ulid(ver)])
coset::cbor::Value::Array(vec![encode_cbor_uuid(id), encode_cbor_uuid(ver)])
},
}
}

#[allow(clippy::indexing_slicing)]
fn decode_cbor_document_ref(val: &coset::cbor::Value) -> anyhow::Result<DocumentRef> {
if let Ok(id) = decode_cbor_ulid(val) {
if let Ok(id) = decode_cbor_uuid(val) {
Ok(DocumentRef::Latest { id })
} else {
let Some(array) = val.as_array() else {
anyhow::bail!("Invalid CBOR encoded document `ref` type");
};
anyhow::ensure!(array.len() == 2, "Invalid CBOR encoded document `ref` type");
let id = decode_cbor_ulid(&array[0])?;
let ver = decode_cbor_ulid(&array[1])?;
let id = decode_cbor_uuid(&array[0])?;
let ver = decode_cbor_uuid(&array[1])?;
Ok(DocumentRef::WithVer { id, ver })
}
}
Expand Down Expand Up @@ -243,11 +222,11 @@ fn build_empty_cose_doc(doc_bytes: Vec<u8>, meta: &Metadata) -> coset::CoseSign
));
protected_header.rest.push((
coset::Label::Text("id".to_string()),
encode_cbor_ulid(&meta.id),
encode_cbor_uuid(&meta.id),
));
protected_header.rest.push((
coset::Label::Text("ver".to_string()),
encode_cbor_ulid(&meta.ver),
encode_cbor_uuid(&meta.ver),
));
if let Some(r#ref) = &meta.r#ref {
protected_header.rest.push((
Expand Down Expand Up @@ -388,7 +367,7 @@ fn validate_cose_protected_header(cose: &coset::CoseSign) -> anyhow::Result<()>
else {
anyhow::bail!("Invalid COSE protected header, missing `id` field");
};
decode_cbor_ulid(value)
decode_cbor_uuid(value)
.map_err(|e| anyhow::anyhow!("Invalid COSE protected header `id` field, err: {e}"))?;

let Some((_, value)) = cose
Expand All @@ -400,7 +379,7 @@ fn validate_cose_protected_header(cose: &coset::CoseSign) -> anyhow::Result<()>
else {
anyhow::bail!("Invalid COSE protected header, missing `ver` field");
};
decode_cbor_ulid(value)
decode_cbor_uuid(value)
.map_err(|e| anyhow::anyhow!("Invalid COSE protected header `ver` field, err: {e}"))?;

if let Some((_, value)) = cose
Expand Down

0 comments on commit b22a672

Please sign in to comment.