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

T

Thibaut Barrère

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
 
J

Jamie Macey

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)]}
 
R

Ryan Davis

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 =3D File.read("/usr/share/dict/words").split
max =3D words.size
puts "#{words[rand(max)]}-#{words[rand(max)]}"

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

Eric pointed me to "bubble babble" which ships in digest and makes the =20=

hash values more readable. It converts your "Xst7JGF6" into "xikal-=20
fytif-ladog-locef-kixox".
require 'digest/bubblebabble'
puts Digest.bubblebabble("Xst7JGF6")

I had no idea that existed... pretty neat.
 
J

John Mettraux

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.

http://github.com/jmettraux/rufus-mnemo


After a "sudo gem install rufus-mnemo"

you can do things like

---8<---
require 'rubygems'
require 'rufus/mnemo'

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

puts s
# =3D> '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,

--=20
John Mettraux - http://jmettraux.wordpress.com
 
D

Dave Bass

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

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

Dave
 
T

Thibaut Barrère

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top