Ruby Ruby Ruby Ruby
June 14, 2008
Parece que fui ao rock in rio ver kaiser chiefs (e fui).
Estava para aqui a brincar ao ruby e assim do nada encontro-me a chamar métodos dinamicamente (ruby as a meta-language) que devolviam strings. Tudo bem até chegar a um que devolvia integer e eis que aparece aquele erro:
NoMethodError in SearchController#search
undefined method `include?’ for 7:Fixnum
Que fazer? Mudar aquela linha de código por um if e contemplar as duas possibilidades? Ou simplesmente alterar o Fixnum e ensinar-lhe o que eu esperava que o include? fizesse? Eu fui pela segunda opção:
class Fixnum
def include?(object)
to_i == object.to_i
end
end
Em linguagens assim dá gosto trabalhar!
Functional vs Imperative: Round 1
April 27, 2008
Imperative in python
Functional on a object oriented flavor in ruby
Note: You can do the opposite, ruby in imperative and python in functional (I’m guessing on the python part, but it’s probably true)
# choose all values from a list that are not in a matrix
# imperative in python
res = []
for value in list:
present = False
for mlist in matrix:
if value in mlist:
present = True
break
if not present:
res.append(value)
# functional in ruby
res = list.select { |value| !matrix.flatten.member? value }
# restrict the matrix to values in list
# imperative strikes back
res = []
for mlist in matrix:
current_mlist = mlist[:]
for mvalue in mlist:
if mvalue not in list:
current_mlist.remove(mvalue)
res.append(current_mlist)
# functional responds
res = matrix.map do |mlist|
mlist.select { |mvalue| list.member? mvalue }
end
ROTD: Having fun with Ruby sort and sort_by methods
April 17, 2008
Simple sorting.
First comes a demonstration of the most common error :P
Then a simple sort
After that comes a first sort_by
And then a complete sort_by (sorted first by fname and then by lname).
>> h = [{'fname' => 'Nuno', 'lname' => 'Job'},
{'fname' => 'Nuno', 'lname' => 'Fonseca'},
{'fname' => 'Catarina', 'lname' => 'Pinto'},
{'fname' => 'Nuno', 'lname' => 'Pinto'},
{'fname' => 'Nuno', 'lname' => 'Antunes'}
]
>> h.sort
NoMethodError: undefined method '< =>' for
{"lname"=>"Job", "fname"=>"Nuno"}:Hash
from (irb):35:in `sort'
from (irb):35
from :0
>> h.sort{|a,b| a['fname'] < => b['fname']}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"},
{"lname"=>"Antunes", "fname"=>"Nuno"}]
>> h.sort_by{|p| p['fname']}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"},
{"lname"=>"Antunes", "fname"=>"Nuno"}]
>> h.sort_by{|p| [p['fname'], p['lname']]}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Antunes", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"}]
Devolvam as passwords aos vossos utilizadores com Ruby on Rails 2.0
February 12, 2008

Uma coisa que me chateia imenso nas webapplications de trazer por casa – traduzindo aquelas que são feitas por colegas meus ou por outros amadores pela web fora – é o facto de guardarem quase sempre as passwords na base de dados em plaintext. Acho que não tem o direito de saber a password que uso, nem que a use exclusivamente nesse site (como é o caso)
Assim, se quem fez a aplicação for mal intencionado, pode simplesmente obter a vossa password escrevendo
select * from users where user.username = 'nick'
Mas mesmo que não sejam mal intencionados, outra pessoa pode aceder a base de dados. Ou podem simplesmente não se ter protegido contra sql injection. Há um milhão de razões pelas quais nunca se deve guardar as password em plaintext, sendo que a principal deles é o facto da password não ser vossa. É do utilizador. E isso faz toda a diferença! Não acreditam em mim certo? Estou a exagerar.
Convido-os a visitar esta página
- http://www.ufp.pt/events.php?intId=10046
Agora procurem por ‘qualquer_coisa. O resultado é
- Pesquisa por “\’qualquer_coisa”:
Este \’ é importantíssimo pois significa que a página se esta a proteger contra ataques de sql injection. Caso contrario um hacker podia, com alguma sorte, obter informação privilegiada que estava contida nessa base de dados.
Mas ninguém faz um erro destes, certo? Errado. Vamos ao google e procurem php em páginas de Portugal. O sexto resultado, e único que testei, é a associação nacional de farmácias. Se procurarem por ‘qualquer_coisa o resultado é um não tão surpreendente erro. Isto é um exemplo de milhares, alguns dos quais onde vocês inserem as vossa password (e sabe-se lá o que mais) diariamente. Não se sentiam melhor se soubessem que nessa base de dados não está a vossa password?
Mas voltando ao assunto, a táctica que vou usar consiste em usar um algoritmo de one way hash chamado SHA. O utilizador, quando se regista no site, insere a sua password. Esta é processada (num processo que se chama de digest) para uma hash que contém não a password mas sim a encriptação dessa password em SHA. Como SHA é um algoritmo de one-way-hash, é fácil obter a hash única para qualquer palavra mas quase impossível de decifrar no sentido inverso. Para ser suficiente, mas não é.
Comecemos por ir para a consola do rails. Entrem no terminal e naveguem até onde tem a vossa Ruby on Rails web application. Agora escrevam.
./script/console
Quando lá estiverem podem verificar que aplicando este algoritmo a palavra porto obtemos sempre a mesma resposta.
>> password = 'porto' => "porto" >> Digest::SHA256.hexdigest(password) => "01735c5ff1608734e4c38449a00b74bb9a8d5423ed548238da70178e9e803483" >> Digest::SHA256.hexdigest(password) => "01735c5ff1608734e4c38449a00b74bb9a8d5423ed548238da70178e9e803483"
Não sei se repararam mas o nosso utilizador usa uma palavra pass muito fraca. Isto vai fazer a diferença, por o hacker pode obter a password facilmente se tiver a hash.
Como? Sim eu disse que era muito difícil crackar o SHA, alias não conheço ninguém que o tenha feito. Ninguém conhece :P
Mas o hacker pode pegar numa lista de palavras comuns nas passwords e, para cada uma das palavras associar a hash correspondente. Agora se tiver a vossa hash pode comparar com o dicionário que criou descobrir algumas das passwords da base de dados, aquelas que estavam na lista de palavras comuns.
Para resolver este problema usamos um salt. Um salt é também uma palavra (como a vossa password) que sera usada para evitar esta técnica. é mais simples mostrar que explicar, e por isso mesmo:
>> password = 'porto'
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
>> salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
=> "19L6gVcD"
>> salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
=> "CqEVe632"
>> password = 'porto'
=> "porto"
>> Digest::SHA256.hexdigest(password + salt)
=> "c017e1c49096149097050c76f0406dce9245058e0d..."
De certeza que o hacker não vai procurar pela string portoCqEVe632 e, portanto, os nossos utilizadores estão seguros. Caso queiram saber um pouco mais sobre o que se passa no criação do salt, e que é aquele pack(‘m’) peçam nos comentários e eu escrevo um artigo sobre isso. Senão nunca mais saio daqui! :P.
Agora surge a pergunta, como usar esta informação em rails. Simples.
Vamos começar por criar um projecto:
rails secureusers && cd secureusers
Agora precisamos de criar o modelo de utilizador
./script/generate model User username:string \ password_hash:string password_salt:string rake db:migrate
Abram o vosso User.rb model, apaguem o que lá tem, e insiram o seguinte código
require 'digest/sha2'
class User < ActiveRecord::Base
# usei o attr_accessible em vez do
# attr_protected :password_hash, :password_salt
# porque é boa prática em Rails usar o enabled para
# os campos acessíveis e não o contrário.
#
# Imaginem que tinham um campo isAdmin e se
# esqueciam de por no protected.
# Ao dizerem que enabled só o :username impedem
# o acesso a todo e qualquer outro campo,
# excepto aqueles que foram explicitamente
# escolhidos por vocês.
attr_accessible :username
attr_accessor :password
def before_save
unless password.blank?
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
self.password_salt, self.password_hash = salt,
Digest::SHA256.hexdigest(password + salt)
end
end
def self.authenticate(username, password)
user = User.find :first,
:conditions => ['username = ?', username])
if user.blank?
raise "O utilizador não existe"
elsif Digest::SHA256.hexdigest(password + user.password_salt) != user.password_hash
raise "A autenticação falhou"
else
user
end
end
end
Usei o attr_accessible em vez do protected porque considero esta uma boa practica. Prefiro dizer quais os campos acessíveis que quais os que se deve proteger. Assim não corro o risco de me esquecer de proteger algum campo. E os que são para ver nota-se bem quando faltam :P Podem ler mais sobre isto aqui.
Depois de toda esta explicação o código deve ser muito facil de entender. Até para quem não sabe Ruby. Vamos testar?
>> nuno = User.new => #<user id: nil, username: nil, password_hash: nil, password_salt: nil, created_at: nil, updated_at: nil> >> nuno.username = 'nuno' => "nuno" >> nuno.password = 'porto' => "porto" >> nuno.save => true >> nuno => #</user><user id: 1, username: "nuno", password_hash: "c490ea11d96be24ece2ca0dba11d84fc9b...", password_salt: "V+b7Sqjh", created_at: "2008-02-12 19:28:54", updated_at: "2008-02-12 19:28:54">
E agora autenticar:
User.authenticate 'nuno', 'porto' => #</user><user id: 1, username: "nuno", password_hash: "c490ea11d96be24ece2ca0dba11d84fc9b...", password_salt: "V+b7Sqjh", created_at: "2008-02-12 19:28:54", updated_at: "2008-02-12 19:28:54">
Fixe. É so por no session[:user] ;) Para finalizar aconselho-vos vivamente a suportarem open-id para o processo de autenticação dos utilizadores. Existem plugins muito bons que o fazem, e podem ler mais sobre open-id no seu fantástico guia supersónico.
e-archia.net
February 12, 2008

Bem a minha primeira aventura em rails chegou a metade. Quem estiver interessado em ver as sources, pode sacar este não-tão-pequeno ficheiro. Senão fica aqui a screenshot. O site não está online porque eu, com a pressa, não tenho a certeza ser fiz escapeHTML ao texto que vem da base de dados. Ficam as screenshots:
Mono developers cannot read .NET code
October 6, 2007
![]()
Well the open-source community never ceases to surprise me. But this time it’s not in a good way. Let’s look to the guidelines so that someone can contribute to mono:
(…)If you have looked at Microsoft’s implementation of .NET or their shared source code, you will not be able to contribute to Mono.(…)
Can I please stop laughing now? I mean you guys are doing a open-source copy of .NET but you state in your own rules that a person cannot read .NET code and help developing mono? It’s rather obvious that you cannot copy proprietary code, but to forbid someone of reading it when it’s publicly available makes no sense. Everyone will read it but not to copy Microsoft’s magic formulas. People just want to know how they pulled it off and then mock them on how lame their solution was! :P
By the way if I email a part of the code to the creators of the mono-project, will the project die? Are you trying to convince anyone that the creators of the project never saw the .NET code when it’s available through reflection? Yeah right!
All this just makes the mono-project look like a bunch of amateurs fundamentalist fools.





