Giter Site home page Giter Site logo

crimp's Introduction

Crimp

Build Status Gem Version

Creates an MD5 hash from simple data structures made of numbers, strings, booleans, nil, arrays or hashes.

Implementations

Crimp Lua Crimp Ruby

Installation

Add this line to your application's Gemfile:

gem 'crimp'

And then execute:

$ bundle

Or install it yourself as:

$ gem install crimp

Usage

require 'crimp'

Crimp.signature({ a: { b: 1 } })
=> "ac13c15d07e5fa3992fc6b15113db900"

Multiplatform design

At the BBC we use Crimp to build keys for database and cache entries.

If you want to build a similar library with your language of choice you should be able to follow the simple specifications defined in spec/crimp_spec.rb. Using these simple rules you will produce a string ready to be MD5 signed.

Once you get your string, is very important to be sure that you can produce the same key in any language. MD5 is your friend:

Ruby

irb(main):001:0> require 'digest'
=> true
irb(main):002:0> Digest::MD5.hexdigest('abc')
=> "900150983cd24fb0d6963f7d28e17f72"

Lua

Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> md5 = require 'md5'
> md5.sumhexa('abc')
900150983cd24fb0d6963f7d28e17f72

Elixir

Erlang/OTP 21 [erts-10.0.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.7.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :crypto.hash(:md5 , "abc") |> Base.encode16() |> String.downcase
"900150983cd24fb0d6963f7d28e17f72"

Node.js

> var crypto = require('crypto');
undefined
> crypto.createHash('md5').update('abc').digest('hex');
'900150983cd24fb0d6963f7d28e17f72'

Fine prints

Symbols

To make Crimp signatures reproducible in any platform we decided to ignore Ruby symbols and treat them as strings, so:

Crimp.signature(:a) == Crimp.Signature('a')

Sets

Also Sets get transformed to Arrays:

Crimp.signature(Set.new(['a', 'b'])) == Crimp.signature(['a', 'b'])

Sorting of collections

Crimp signatures are generated against sorted collections.

Crimp.signature([1, 2]) == Crimp.signature([2, 1])
Crimp.signature({'b' => 2, 'a' => 1}) == Crimp.signature({'a' => 1, 'b' => 2})

Crimp also sorts nested collections.

Crimp.signature([1, [3, 2], 4]) == Crimp.signature([4, [2, 3], 1])
Crimp.signature({'b' => {'d' => 2,'c' => 1}, 'a' => [3, 1, 2]}) == Crimp.signature({'a' => [1, 2, 3], 'b' => { 'c' => 1, 'd' => 2 }})

Custom objects

Crimp will complain if you try to get a signature from an instance of some custom object:

Crimp.signature(Object.new)
=> TypeError: Expected a (String|Number|Boolean|Nil|Hash|Array), Got Object

It is your responsibility to pass a compatible representation of your object to Crimp.

Implementation details

Under the hood Crimp annotates the passed data structure to a nested array of primitives (strings, numbers, booleans, nils, etc.) and a single byte to indicate the type of the primitive:

Type Byte
String S
Number N
Boolean B
nil _
Array A
Hash H

You can verify it using the #annotate method:

Crimp.annotate({ a: 1 })
=> [[[[[1, "N"], ["a", "S"]], "A"]], "H"]

Notice how Crimp marks the collection as Hash (H) and then transforms the tuple of key/values to an Array (A).

Here's an example with nested hashes:

Crimp.annotate({ a: { b: 'c' } })
=> [[[[["a", "S"], [[[[["b", "S"], ["c", "S"]], "A"]], "H"]], "A"]], "H"]

Before signing Crimp transforms the collection of nested array to a string.

Crimp.notation({ a: { b: 'c' } })
=> "aSbScSAHAH"

Please note the Arrays and Hash keys are sorted before signing.

Crimp.notation([3, 1, 2])
=> "1N2N3NA"

key/value tuples get sorted as well.

Crimp.notation({ a: 1 })
=> "1NaSAH"

Changelog

Version Changes
v0.x Original version of Crimp.
v0.2.0 Crimp compatibility with Ruby >= 2.4, use this for legacy projects.
v1.0.0 Includes breaking changes and returns different signatures from v0.2

Contributing

  1. Fork it ( http://github.com/BBC-News/crimp/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

crimp's People

Contributors

ettomatic avatar kenoir avatar samfrench avatar integralist avatar alexmuller avatar

Stargazers

Ilia Lobsanov avatar Jason Dougherty avatar  avatar  avatar Henrique A. Lavezzo avatar Justin Gordon avatar Peter Boling avatar Rick Song avatar Eliot Sykes avatar Christoph Grabo avatar Floyd Arguello avatar  avatar Pete Doherty avatar Chee Yeo avatar Gary Lai avatar

Watchers

Matt Haynes avatar Jeremy Tarling avatar Tom Maslen avatar John Cleveley avatar Oliver Godby avatar Aodh O Lionaird avatar Andrew Fulcher avatar  avatar Tian Yuan avatar James Cloos avatar Stefano Belloro avatar Wayne McManus avatar Alasdair Stalker avatar Richard Lynton-Evans avatar Steve Wheeler avatar Bogdan Dogaru avatar Alfonso Afonso avatar James Donohue avatar BBC News Frameworks avatar Chris Hopkins avatar James Bowers avatar  avatar

crimp's Issues

Returns the same result for [] and {}

Not sure if this is desired behavior or not, but I'd assume that empty array [] and empty hash {} should be different.

Crimp.stringify([]) -> []Array
Crimp.stringify({}) -> []Array

Returns the same result for [1,2,3] and [3,2,1] (all arrays are sorted)

The self.parse_array function sorts all arrays. That seems like odd behavior, but perhaps that's intended?

Crimp.stringify([1,2,3]) -> [\"1Fixnum\", \"2Fixnum\", \"3Fixnum\"]Array
Crimp.stringify([3,2,1]) -> [\"1Fixnum\", \"2Fixnum\", \"3Fixnum\"]Array

I presume the sort is to fix hash order problems, but perhaps better would be to explicitly sort just the hashes?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.