Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customizing semantic tags decoding. #120

Open
jkerdreux-imt opened this issue Sep 29, 2021 · 6 comments
Open

Customizing semantic tags decoding. #120

jkerdreux-imt opened this issue Sep 29, 2021 · 6 comments

Comments

@jkerdreux-imt
Copy link

I'm looking for a way to customize tag decoder that are already handled by the cbor2 lib by itself.

semantic_decoders provides a list of functions to call tag decoding. I used a ugly trick to change the default decoding of uuids from uuid.UUID to my custom binding.UUID. Using this trick allows me to handle encoding and decoding of internal UUID the same way, without the need to walk through all objects to change uuid.UUID to internal type.

Here the piece of code :
https://redmine.telecom-bretagne.eu/projects/xaal/repository/entry/code/Python/branches/0.7/libs/lib/xaal/lib/cbor.py#L7

But, this is a trick and only works for the python cbor2 package, not the _cbor2 C code, and worst it fails silently if _cbor2 is loaded.

Is there a way to write this without any trick ? The CBORDecoder calls functions directly from semantics_decoders. There is no way to customize the CBORDecoder itself without overriding the _decode method (not really something I want to do).

Is there a way to disable _cbor2 at runtime ? (not the best option but...)

Thanks for any help.

@Sekenre
Copy link
Collaborator

Sekenre commented Oct 3, 2021

I agree this is a problem. I think integrating semantic tag handling into the C-module wasn't the right move. I'll see if I can find a workaround for you.

@Sekenre
Copy link
Collaborator

Sekenre commented Oct 3, 2021

I've had a look at the code and I suggest the way to maintain speed is to use a custom tag for your custom type. E.g.

import cbor2
import bindings

def default_encoder(encoder, value, **kwargs):
  if isinstance(value, bindings.UUID):
    encoder.encode(cbor2.CBORTag(50012, value.bytes))

def tag_hook(decoder, tag, shareable_index=None):
  if tag.tag == 50012:
    return bindings.UUID(bytes=tag.value)

def dumps(obj, **kwargs):
  return cbor2.dumps(obj,default=default_encoder,**kwargs)

def loads(payload, **kwargs):
  return cbor2.loads(payload,tag_hook=tag_hook,**kwargs)

This will get you the behaviour you want without slowing down the decoder.

@jkerdreux-imt
Copy link
Author

This code is part of an xAAL encoder/decoder (xAAL is a home automation protocol), so I can't use a unassigned tag. That's why I used this trick.

Thanks

@Sekenre
Copy link
Collaborator

Sekenre commented Oct 6, 2021

It may be possible to monkey-patch the builtin UUID library before importing cbor2. This should work since the cbor2 module imports uuid.UUID

@textshell
Copy link

Allowing to override the handling of semantic tags should also be useful for security hardening. cbor2 seems to be much saner than what was done in the past with regard to deserialization code, but it's always good to limit how much unneeded code in reachable.

The way how major_decoders and semantic_decoders are currently module globals makes this very hard to customize via inheritance or on an instance level, because they make it impossible override the methods that handle these cases as the methods are called without looking in the actual class.

It seem currently the following monkey patch allows overriding decode_semantic:

# monkey patch cbor2 to actually use overloads in subclasses.
cbor2.decoder.major_decoders[6] = lambda self, subtype: self.decode_semantic(subtype)

But that's of course quite hacky.

@Sekenre
Copy link
Collaborator

Sekenre commented Jun 26, 2022

@textshell I've been working on this for the next version here: https://github.com/Sekenre/cbor2/blob/version-6/source/decoder.c#L963

Haven't had time to finish it off yet but it's close to being ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants