{"id":17038632,"url":"https://github.com/wbotelhos/idy","last_synced_at":"2025-04-12T13:52:50.819Z","repository":{"id":20618981,"uuid":"90443214","full_name":"wbotelhos/idy","owner":"wbotelhos","description":":eyeglasses: An ID obfuscator for ActiveRecord","archived":false,"fork":false,"pushed_at":"2023-05-25T14:20:00.000Z","size":91,"stargazers_count":22,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-10T03:54:00.304Z","etag":null,"topics":["activerecord","crypto","hash","hashids","mask","obfuscation","obfuscator","rails","salt","url-shortener"],"latest_commit_sha":null,"homepage":"https://www.danca.com","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/wbotelhos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"wbotelhos"}},"created_at":"2017-05-06T06:46:00.000Z","updated_at":"2025-03-28T10:01:24.000Z","dependencies_parsed_at":"2022-08-07T09:16:11.564Z","dependency_job_id":null,"html_url":"https://github.com/wbotelhos/idy","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wbotelhos%2Fidy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wbotelhos%2Fidy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wbotelhos%2Fidy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wbotelhos%2Fidy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wbotelhos","download_url":"https://codeload.github.com/wbotelhos/idy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248576370,"owners_count":21127380,"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","crypto","hash","hashids","mask","obfuscation","obfuscator","rails","salt","url-shortener"],"created_at":"2024-10-14T08:57:18.876Z","updated_at":"2025-04-12T13:52:50.794Z","avatar_url":"https://github.com/wbotelhos.png","language":"Ruby","funding_links":["https://patreon.com/wbotelhos","https://www.patreon.com/wbotelhos"],"categories":["Ruby"],"sub_categories":[],"readme":"# Idy\n\n[![CI](https://github.com/wbotelhos/idy/workflows/CI/badge.svg)](https://github.com/wbotelhos/idy/actions)\n[![Gem Version](https://badge.fury.io/rb/idy.svg)](https://badge.fury.io/rb/idy)\n[![Maintainability](https://api.codeclimate.com/v1/badges/f312587b4f126bb13e85/maintainability)](https://codeclimate.com/github/wbotelhos/idy/maintainability)\n[![Coverage](https://codecov.io/gh/wbotelhos/idy/branch/main/graph/badge.svg?token=rKcyNTwHjn)](https://codecov.io/gh/wbotelhos/idy)\n[![Sponsor](https://img.shields.io/badge/sponsor-%3C3-green)](https://www.patreon.com/wbotelhos)\n\nAn ID obfuscator for ActiveRecord.\n\n## Description\n\nDo not let your users knows about your IDs:\n\n- IDs can make hacker's life easier for a sequential attack;\n- IDs can make crawler's life easier for a sequential scan;\n- With few records on your database it can seem that your business is weak;\n- With many records on your database it can call attention of people.\n\n*Make it clean, make it lean, make it hidden.*\n\n`http://example.com/articles/1` -\u003e `http://example.com/articles/My`\n\nIt uses [Hashids](http://hashids.org/ruby) to make it pretty.\n\n## install\n\nAdd the following code on your `Gemfile` and run `bundle install`:\n\n```ruby\ngem 'idy'\n```\n\n## Usage\n\nOn an `ActiveRecord` model, just add `idy` callback:\n\n```ruby\nclass Article \u003c ApplicationRecord\n  idy\nend\n```\n\nTry to call on your model the obfuscated ID:\n\n```ruby\nArticle.new(id: 1).idy\n# My\n```\n\nIt will build your Rails URL with that ID too:\n\n```ruby\nArticle.new(id: 1).to_param\n# localhost:3000/articles/My\n```\n\n## Security\n\nIdy is not for encryption, it is about obfuscation.\nIf you want a *unbreakable* hash, it is not for you.\n\n## Collision\n\nTo avoid two differents models to generates the same hash for the same ID,\nby default, the class name is used as a [Salt](https://en.wikipedia.org/wiki/Salt_cryptography).\n\n```ruby\nArticle.new(id: 1).idy\n# My\n\nUser.new(id: 1).idy\n# ex\n```\n\n## Salt\n\nYou can provide you own:\n\n```ruby\nclass Article \u003c ApplicationRecord\n  idy salt: 's3cr3t'\nend\n```\n\n```ruby\nArticle.new(id: 1).idy\n# 9A\n```\n\n## Idy\n\nAs you could see, the method `idy`, returns the hash representation of your ID:\n\n```ruby\nArticle.new(id: 1).idy\n# My\n```\n\nIf you want get all idys from a collection, just map it:\n\n```ruby\nArticle.create\nArticle.create\n\nArticle.select(:id).map(\u0026:idy)\n# [\"My\", \"aL\"]\n```\n\n## Find\n\nSince you add the `idy` callback to your model, `find` method will be decorated:\n\n```ruby\nArticle.find('My').id\n# 1\n```\n\nKeep in mind that if you have some internal code, that you cannot change,\nusing `find`, the hash version of the id, `idy`, will be mandatory to correct find the record.\n\n## Findy and Findy!\n\nWe encourage you to use this methods and avoid tweak `find` Rails method. As you expect, it will find directly via idy, so a normal integer will be not found, even if it exists on database.\n\n### Findy\n\nThe bumpless version returns `nil` when record is not found.\n\n```ruby\nArticle.findy('My').id\n# 1\n\nArticle.findy 'missing'\n# nil\n```\n\n### Findy!\n\nThe bump `!` version raises an error when record is not found.\n\n```ruby\nArticle.findy!('My').id\n# 1\n\nArticle.findy! 'missing'\n# ActiveRecord::RecordNotFound: Couldn't find Article with 'idy'=\"missing\"\n```\n\n## Functions\n\nYou can encode a number manually:\n\n```ruby\nModel.idy_encode(idy)\n```\n\nYou can decode an idy in case you want to use the ActiveRecord methods with the original ID:\n\n```ruby\nModel.idy_decode(idy)\n```\n\n## Testing\nCheck if your model responds to idy method:\n\n### RSpec\n```ruby\nit { is_expected.to respond_to(:idy) }\n```\n\n## Inspiration\n\nIt was inspired and improved from:\n\n- [obfuscate_id](https://github.com/namick/obfuscate_id)\n- [hashids_uri](https://github.com/danieldraper/hashids_uri)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwbotelhos%2Fidy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwbotelhos%2Fidy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwbotelhos%2Fidy/lists"}