{"id":19711706,"url":"https://github.com/brightcommerce/attr_digest","last_synced_at":"2025-04-29T18:30:46.195Z","repository":{"id":56842639,"uuid":"51810214","full_name":"brightcommerce/attr_digest","owner":"brightcommerce","description":"Provides functionality to store a hash digest of an attribute using Argon2","archived":false,"fork":false,"pushed_at":"2018-02-15T05:53:58.000Z","size":40,"stargazers_count":5,"open_issues_count":4,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-20T22:49:29.427Z","etag":null,"topics":["activerecord","argon","argon2","attributes","digest","hashing","password"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brightcommerce.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-16T05:21:31.000Z","updated_at":"2019-01-07T01:19:58.000Z","dependencies_parsed_at":"2022-09-01T06:32:22.158Z","dependency_job_id":null,"html_url":"https://github.com/brightcommerce/attr_digest","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_digest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_digest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_digest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_digest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brightcommerce","download_url":"https://codeload.github.com/brightcommerce/attr_digest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251559728,"owners_count":21609063,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","argon","argon2","attributes","digest","hashing","password"],"created_at":"2024-11-11T22:13:27.167Z","updated_at":"2025-04-29T18:30:45.871Z","avatar_url":"https://github.com/brightcommerce.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Gem Version](https://badge.fury.io/rb/attr_digest.svg)](https://badge.fury.io/rb/attr_digest)\n[![Build Status](https://travis-ci.org/brightcommerce/attr_digest.svg?branch=master)](https://travis-ci.org/brightcommerce/attr_digest)\n[![codecov.io](https://codecov.io/github/brightcommerce/attr_digest/coverage.svg?branch=master)](https://codecov.io/github/brightcommerce/attr_digest?branch=master)\n[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/brightcommerce/attr_digest/pulls)\n\n# AttrDigest\n\n[**AttrDigest**](https://github.com/brightcommerce/attr_digest) provides functionality to store a hash digest of an attribute using [Argon2](https://github.com/P-H-C/phc-winner-argon2).\n\nArgon2 is a password-hashing function that summarizes the state of the art in the design of memory-hard functions and can be used to hash passwords for credential storage, key derivation, or other applications. It  is the official winner and recommendation of the [Password Hashing Competition (PHC)](https://password-hashing.net) which ran between 2013 and 2015.\n\nThis Gem uses the [Ruby Argon2 Gem](https://github.com/technion/ruby-argon2) which provides FFI bindings, and a simplified interface, to the Argon2 algorithm.\n\n**AttrDigest** provides similar functionality to Rails `has_secure_password`, but permits any number attributes to be hashed in a model, and obviously you're not limited to just the `password` attribute.\n\n## Installation\n\nTo install add the following line to your `Gemfile`:\n\n``` ruby\ngem 'attr_digest'\n```\n\nAnd run `bundle install`.\n\n## Dependencies\n\nRuntime:\n- activerecord (\u003e= 4.2.6)\n- activesupport (\u003e= 4.2.6)\n- argon2 (= 1.1.3) ** See CHANGELOG.md for version lock reason\n\nDevelopment/Test:\n- rake (~\u003e 10.5)\n- rspec (~\u003e 3.4)\n- sqlite3 (~\u003e 1.3)\n- simplecov (~\u003e 0.11.2)\n- factory_girl (~\u003e 4.5)\n\n## Compatibility\n\nTested with Ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin16] against ActiveRecord 5.2.0.rc1 on macOS High Sierra 10.13.3 (17D47).\n\nArgon2 requires Ruby 2.2 minimum and an OS platform that supports Ruby FFI Bindings, so unfortunately Windows is out.\n\n## Usage\n\nAttributes to be digested are declared using the `attr_digest` class method in your model:\n\n```ruby\nActiveRecord::Schema.define do\n  create_table :users, force: true do |t|\n    t.string :security_question, null: false\n    t.string :security_answer_digest, null: false\n  end\nend\n\nclass User \u003c ActiveRecord::Base\n  attr_digest :security_answer\nend\n```\n\n**AttrDigest** automatically creates the `#security_answer` getter and `#security_answer=` setter. The setter creates a digest of the value provided and stores it in the `security_answer_digest` column.\n\n**AttrDigest** also defines the method `authenticate_security_answer(value)` which returns `false` if the `value` given does not correspond to the saved digest, or returns `true` if it does.\n\n### Validations\n\n**AttrDigest** adds some default validations. Using the example above:\n* it creates a `confirmation` validation on `security_answer`, but only if `security_answer` is given (for confirmation validations see [ActiveRecord Validations](http://http://guides.rubyonrails.org/active_record_validations.html#confirmation)).\n* it creates a `presence` validation on `security_answer` but only on `create`.\n* it creates a `presence` validation on `security_answer_confirmation` but only if `security_answer` has been given; and\n* it raises an `exception` if `security_answer_digest` is empty on `create`.\n\nYou can disable all validations by passing `false` to the `validations` option:\n\n```ruby\nattr_digest :security_answer, validations: false\n```\n\n#### Case Sensitivity\n\nIf you want values passed to be case insensitive, you can pass `false` to the `case_sensitive` option:\n\n```ruby\nattr_digest :security_answer, case_sensitive: false\n```\n\nThen differing cases will match, e.g. `pizza` will match `PizzA`.\n\n#### Confirmations\n\nIf you prefer to skip confirmations for the attribute you are hashing, you can pass `false` to the `confirmation` option:\n\n```ruby\nattr_digest :security_answer, confirmation: false\n```\n\n#### Format\n\nYou can ensure the attribute you are hashing matches a given regular expression by passing a `format` option:\n\n```ruby\nattr_digest :password, format: { with: /\\A[a-zA-Z]+\\z/, message: \"only allows letters\" }\n```\n\nAttrDigest adds the Rails format validator and passes the options hash through as is. See [Active Record Validations format validator](http://edgeguides.rubyonrails.org/active_record_validations.html#format) for options you can pass to the `format` options hash.\n\n**NOTE:** The `format` option is not affected by the `validations` option. Adding the `format` option will add a Rails format validator *regardless* of whether the `validations` option is set to `true` or `false`.\n\n#### Length\n\nYou can ensure the attribute your are hashing meets certain length criteria by passing a `length` option:\n\n```ruby\nattr_digest :password, length: { minimum: 5 }\nattr_digest :password, length: { maximum: 10 }\nattr_digest :password, length: { in: 5..10 }\nattr_digest :password, length: { is: 8 }\n```\n\nAttrDigest adds the Rails length validator and passes the options hash through as is. See [Active Record Validations length validator](http://edgeguides.rubyonrails.org/active_record_validations.html#length) for options you can pass to the `length` options hash.\n\n**NOTE:** The `length` option is not affected by the `validations` option. Adding the `length` option will add a Rails length validator *regardless* of whether the `validations` option is set to `true` or `false`.\n\n### Protected Digest Setter\n\nIf you want to prevent the attribute's digest being set directly, you can include the `protected` option:\n\n```ruby\nattr_digest :security_answer, protected: true\n```\n\nThe attribute's digest is *not* protected from direct setting by default.\n\n### Time and Memory Costs\n\n**AttrDigest** sets a default time and memory cost and expects the following minimum and maximum values:\n\nOption | Minimum Value | Maximum Value | Default Value\n--- | --- | --- | ---\n:time_cost | 1 | 10 | 2\n:memory_cost | 1 | 31 | 16\n\nYou can change the global defaults by setting the cost options directly on the `AttrDigest` class:\n\n```ruby\nAttrDigest.time_cost = 3\nAttrDigest.memory_cost = 12\n```\n\nYou can also change the time and memory cost for a specific attribute by passing the options to the `attr_digest` class method in your model:\n\n```ruby\nattr_digest :security_answer, time_cost: 3, memory_cost: 12\n```\n\n### Secret Key\n\nArgon2 supports an optional secret key value. This should be stored securely on your server, such as alongside your database credentials. Hashes generated with a secret key will only validate when presented that secret.\n\nYou can set the optional secret key globally by setting the `secret` attribute on the `AttrDigest` class:\n\n```ruby\nAttrDigest.secret =  Rails.application.secrets.secret_key_base\n```\n\nYou can also set the optional secret key for a specific attribute by passing the `:secret` option to the `attr_digest` class method in your model:\n\n```ruby\nattr_digest :security_answer, secret: Rails.application.secrets.secret_key_base\n```\n\n## Tests\n\nTests are written using Rspec, FactoryGirl and Sqlite3. There are 52 examples with 100% code coverage.\n\nTo run the tests, execute the default rake task:\n\n``` bash\nbundle exec rake\n```\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## Credit\n\nI would like to thank [Panayotis Matsinopoulos](http://www.matsinopoulos.gr) for his [has_secure_attribute](https://github.com/pmatsinopoulos/has_secure_attribute) gem which provided a lot of the inspiration and framework for **AttrDigest**.\n\nI would also like to thank [Lawrence Sproul](https://github.com/Lawrence-Sproul) for bringing to light some potential error conditions,  providing the motivation to make the gem feature complete and the inspiration for additional validation options.\n\nThis gem was written and is maintained by [Jurgen Jocubeit](https://github.com/JurgenJocubeit), CEO and President Brightcommerce, Inc.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Copyright\n\nCopyright 2016-2017 Brightcommerce, Inc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrightcommerce%2Fattr_digest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrightcommerce%2Fattr_digest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrightcommerce%2Fattr_digest/lists"}