Changelog — Thorn 1.3.0 documentation

# Changelog

## 1.3.0

release-date: | 2016-07-07 07:40 P.M PDT
release-by: | Ask Solem

- New and improved method for HMAC signing.

  > The new method must be enabled manually by setting:

  >     THORN_HMAC_SIGNER = 'thorn.utils.hmac:sign'

  > It turns out itsdangerous did not do what we expected it to, instead it does this:

  > - The secret key is transformed into:

  >   >      key = hashlib.sha256(salt + 'signer' + HMAC_SECRET)
  >   >     # strip = from beginning and end of the base64 string
  >   >     key = key.strip('=')

  > - If you don’t specify a salt, which we don’t, there is a default salt(!) which is:

  >       “itsdangerous.Signer”

  > - The extra “signer” in the key transformation is there as the default key_derivation method is called “django-concat”.

  > - The final signature is encoded using “urlsafe_b64encode”

  >   > So in Python to recreate the signature using the built-in hmac library you would have to do:

  >   >     import hashlib
  >   >     import hmac
  >   >     from base64 import urlsafe_b64encode

  >   >     # everything hardcoded to SHA256 here

  >   >     def create_signature(secret_key, message):
  >   >         key = hashlib.sha256(
  >   >             'itsdangerous.Signer' + 'signer' + secret_key).digest()
  >   >         digest = hmac.new(key, message, digestmod=hashlib.sha256).digest()
  >   >         return urlsafe_b64encode(digest).replace('=')

  >   > which is much more complicated than what we can expect of users.

  > You’re highly encouraged to enable the new HMAC method, but sadly it’s not backwards compatible.

  > We have also included new examples for verifying HMAC signatures in Django, Ruby, and PHP in the documentation.

- New `THORN_SUBSCRIBER_MODEL` setting.

- New `THORN_HMAC_SIGNER` setting.

- Requirements: Tests now depends on case 1.2.2

- JSON: Make sure simplejson does not convert `Decimal` to `float`.

- class:~thorn.events.ModelEvent: name can now be a string format.

  > Contributed by Flavio Curella.

  > The format expands using the model instance affected, e.g:

  >     on_created=ModelEvent('created.{.occasion}')

  > means the format will expand into `instance.occasion`.

  > Subclasses of `ModelEvent` can override how the name is expanded by defining the `_get_name` method.

## 1.2.1

release-date: | 2016-06-06 06:30 P.M PDT
release-by: | Ask Solem

- Celery: Forward event signal context to the tasks.

## 1.2.0

release-date: | 2016-06-02 01:00 P.M PDT
release-by: | Ask Solem

- Event: Adds `request_data` option.

  > This enables you to inject additional data into the webhook payload, used for integration with quirky HTTP endpoints.

- Event: Adds `allow_keepalive` option.

  > HTTP connections will not be reused for an event if this flag is set to False. Keepalive is enabled by default.

- Event: Adds `subscribers` argument that can be used to add default subscribers for the event.

  > This argument can hold the same values as the `THORN_SUBSCRIBERS` setting.

- Decorator: `model.webhook_events` is now a UserDict proxy

    to `model.webhook_events.events`.

- Subscriber: `thorn.generic.models.AbstractSubscribers` is a new abstract interface for subscriber models.

  > This should be used if you want to check if an object is a subscriber in `isinstance()` checks.

- Q: `now__*` operators now properly handles the case when there’s

    no previous version of the object.

- Django: `django.db.models.signals.pre_save` signal handler now ignores `ObjectDoesNotExist` errors.

- Events: Adds new `prepare_recipient_validators` method, enabling subclasses to e.g. set default validators.

- Windows: Unit test suite now passing on win32/win64.

- Module `thorn.models` renamed to `thorn.generic.models`.

## 1.1.0

release-date: | 2016-05-23 12:00 P.M PDT
release-by: | Ask Solem

- Fixed installation on Python 3

  > Fix contributed by Josh Drake.

- Now depends on

  > - itsdangerous
  > - ipaddress (Python 2.7)

- Security: Now provides HMAC signing by default.

  > The Subscriber model has a new `hmac_secret` field which subscribers can provide to set the secret key for communication. A default secret will be created if none is provided, and can be found in the response of the subscribe endpoint.

  > The signed HMAC message found in the `Hook-HMAC` HTTP header can then be used to verify the sender of the webhook.

  > An example Django webhook consumer verifying the signature can be found in the Django guide.

  > Thanks to Timothy Fitz for suggestions.

- Security: No longer dispatches webhooks to internal networks.

  > This means Thorn will refuse to deliver webhooks to networks considered internal, like `fd00::/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` and `127.0.0.1`

  > This behavior can be changed globally using the `THORN_RECIPIENT_VALIDATORS` setting, or on an per-event basis using the `recipient_validators` argument to `event`.

- Security: Now only dispatches to HTTP and HTTPS URLs by default.

  > This behavior can be changed globally using the `THORN_RECIPIENT_VALIDATORS` setting, or on an per-event basis using the `recipient_validators` argument to `event`.

- Security: Now only dispatches to ports 80 and 443 by default.

  > This behavior can be changed globally using the `THORN_RECIPIENT_VALIDATORS` setting, or on an per-event basis using the `recipient_validators` argument to `event`.

- Security: Adds recipient validators

  > You can now validate the recipient URL by providing a list of validators in the `recipient_validators` argument to `Event`.

  > The default list of validators is provided by the new `THORN_RECIPIENT_VALIDATORS` setting.

  > Thanks to Edmond Wong for reviewing, and Timothy Fitz for suggestions.

- Django: Now properly supports custom user models by using `UserModel.get_username()`.

  > Fix contributed by Josh Drake.

- ModelEvent: Adds new many-to-many signal dispatcher types

  > - `dispatches_on_m2m_add(related_field)`

  >   > Sent when a new object is added to a many-to-many relation.

  > - `dispatches_on_m2m_remove(related_field)`

  >   > Sent when an object is removed from a many-to-many relation.

  > - `dispatches_on_m2m_clear(related_field)`

  >   > Sent when a many-to-many relation is cleared.

  > Example

  > In this blog article model, events are sent whenever a new tag is added or removed:

  >     @webhook_model(
  >         on_add_tag=ModelEvent(
  >             'article.tagged').dispatches_on_m2m_add('tags'),
  >         on_remove_tag=ModelEvent(
  >             'article.untagged').dispatches_on_m2m_remove('tags'),
  >         on_clear_tags=ModelEvent(
  >             'article.tags_cleared').dispatches_on_m2m_clear('tags'),
  >     )
  >     class Article(models.Model):
  >         title = models.CharField(max_length=128)
  >         tags = models.ManyToManyField(Tag)

  >     class Tag(models.Model):
  >         name = models.CharField(max_length=64, unique=True)

  > The `article.tagged` webhook is sent when:

  >     >>> python_tag, _ = Tag.objects.get_or_create(name='python')
  >     >>> article.tags.add(python_tag)  # <-- dispatches with this line

  > and the `article.untagged` webhook is sent when:

  >     >>> article.tags.remove(python_tag)

  > finally, the `article.tags_cleared` event is sent when:

  >     >>> article.tags.clear()

- Documentation fixes contributed by:

  > - Matthew Brener

## 1.0.0

release-date: | 2016-05-13 10:10 A.M PDT
release-by: | Ask Solem

- Initial release :o)