Options to generate small, kind of unique, human-readable tokens (like "V0cM9tnV")?

Hi,

I’m pretty sure there is a number of options to achieve this, so I’m
asking here. I often need to generate small unique tokens (like for
invitation codes or unimportant authentication token).

In the past I’ve been using Digest::SHA1.hexdigest(some string) which
gives us something like “d2b7882fa08bb6de8dca62f16298683bfe4f0738”.
It’s not very user friendly though, and definitely not small.

More recently I’ve been using ActiveSupport::SecureRandom.base64(6)
which generates “Xst7JGF6” or “zXxWY/Y/”, but sometimes it contains
non-url friendly characters like “/”.

What do you use ? Is there a specific gem to achieve this in a robust
fashion (= making collisions unlikely, and specify the characters to
be used, like mixture of numbers and characters for instance ?)

cheers and thanks for your input,

Thibaut

On Dec 29, 4:44 am, Thibaut Barrère [email protected] wrote:

Hi,

I’m pretty sure there is a number of options to achieve this, so I’m
asking here. I often need to generate small unique tokens (like for
invitation codes or unimportant authentication token).

In the past I’ve been using Digest::SHA1.hexdigest(some string) which
gives us something like “d2b7882fa08bb6de8dca62f16298683bfe4f0738”.
It’s not very user friendly though, and definitely not small.

I’ve mostly just used a substring on SHA1 - hexdigest[8…16] is small
enough to be usable, but still pseudo-random enough for temporary
tokens to not be guessable.

More recently I’ve been using ActiveSupport::SecureRandom.base64(6)
which generates “Xst7JGF6” or “zXxWY/Y/”, but sometimes it contains
non-url friendly characters like “/”.

Base64 is A-Za-z0-9/-. Gsub / for _ and you’re pretty url friendly.

What do you use ? Is there a specific gem to achieve this in a robust
fashion (= making collisions unlikely, and specify the characters to
be used, like mixture of numbers and characters for instance ?)

Lastly, not terribly robust, but functional:

chars = [‘A’…‘Z’, ‘a’…‘z’, ‘0’…‘9’].map{|r|r.to_a}.flatten
Array.new(6).map{chars[rand(chars.size)]}

On Dec 29, 2008, at 01:44 , Thibaut Barrère wrote:

In the past I’ve been using Digest::SHA1.hexdigest(some string) which
gives us something like “d2b7882fa08bb6de8dca62f16298683bfe4f0738”.
It’s not very user friendly though, and definitely not small.

I personally think the following is really cute:

words = File.read("/usr/share/dict/words").split
max = words.size
puts “#{words[rand(max)]}-#{words[rand(max)]}”

and can generate 55194924096 different very readable combinations.
I’ll leave it to you to actually make them unique rather than random
picks.

Eric pointed me to “bubble babble” which ships in digest and makes the
hash values more readable. It converts your “Xst7JGF6” into “xikal-
fytif-ladog-locef-kixox”.

require ‘digest/bubblebabble’

puts Digest.bubblebabble(“Xst7JGF6”)

I had no idea that existed… pretty neat.

On Mon, Dec 29, 2008 at 6:44 PM, Thibaut Barrère
[email protected] wrote:

Hi,

I’m pretty sure there is a number of options to achieve this, so I’m
asking here. I often need to generate small unique tokens (like for
invitation codes or unimportant authentication token).

In the past I’ve been using Digest::SHA1.hexdigest(some string) which
gives us something like “d2b7882fa08bb6de8dca62f16298683bfe4f0738”.
It’s not very user friendly though, and definitely not small.

Hi Thibaut,

I have this rufus-mnemo that turns integers into “user friendly”
strings.

After a “sudo gem install rufus-mnemo”

you can do things like

—8<—
require ‘rubygems’
require ‘rufus/mnemo’

s = Rufus::Mnemo::from_integer(125704)

puts s
# => ‘karasu’
—>8—

Not exactly what you want, but could be funny. It’s using a restricted
syllabary (the Japanese one) to turn integers into words (and back).

As twittered, it has the potential to generate insulting words. The
generated syllables sequences are quite easy to the latin ears though.

Best regards, meilleurs voeux pour 2009,

Hey guys,

just want to say thank you all for the feedback and these options.
I’ll gather these into a blog post later today, I think it’s worth
sharing.

Thanks again!

Thibaut

Generate a suitable random (or otherwise) integer and express in base
36:

puts rand(36**6).to_s(36)

Dave