MiniUri
Generate short(ish), practically unguessable URI for app models, implemented in Plain Old Ruby. MiniUri uses reflection to create uniquely identifiable URI, so Foo.new.to_muri
and Bar.new.to_muri
will be different. Should your app use MiniUri to issue permalinks, the links are no longer valid if the secret changes or, as a result of the reflection if the namespace of your class changes (change module, change class name, etc).
NOTE: MiniUri is meant for a specific use case. It was designed for issuing links to "protected" or "unlisted" resources. Despite a cryptographic review, and the potential for use outside this use case, at this time I recommend it be used strictly for sharing unlisted resources (things that are public, but that you'd rather not have the masses and web crawlers have access to, like a sign-in portal tailored to a user or client). A future goal of this project is to allow for pre-authorized actions, however I will wait to see how the gem fares in the wild first.
Please load your secret to ENV['MINI_URI_SECRET']
, MiniUri assumes no responsibility for your secret. Please make sure it is securely stored, and generated by a good random number generator. A good secret should be 256 bits in length.
NOTE: many secrets are encoded and stored as hex or base64, it is advised to remove the encoding or else risk diluting the entropy of your secret, for hex you can do the following (ruby 2):
secret = '000E0000000000'
secret.length
# => 14
ENV["MINI_URI_SECRET"] = [secret].pack('H*')
ENV["MINI_URI_SECRET"].length
# => 7
For Base64 use the appropriate method in the Base64 standard library
Installation
gem install mini_uri
Usage
Include MiniUri in any of your app's models.
require 'mini_uri'
class User
include MiniUri
attr_accessor :id
end
MiniUri assumes the model class has an integer attribute :id
since this is the common practice, however you can generate on any integer value you want.
ENV['MINI_URI_SECRET'] = 'this is a bad secret'
user = User.new
user.id = 12345
user.to_muri
# => "3D7-6xtqryABGqkHNGSieho1Do"
User.new.to_muri(12345)
# => "3D7-6xtqryABGqkHNGSieho1Do"
now say you have an endpoint /user/:mini_uri
, in the corresponding controller you could retrieve the actual id and record
def show
id = User.muri_to_id(params[:mini_uri])
if id == nil
render_404
else
@user = User.find(id)
end
end