Posts de November, 2010

[Rafael Biriba] HTML5: Trocando mensagens entre a página e iframes

Saturday, November 27th, 2010

Por questões de segurança e privacidade, os navegadores impedem que haja comunicação entre os conteúdo de diferentes domínios. Ou seja, scripts em diferentes dominios (cross-domain) não podem se interagir.

Na prática seria assim… Já imaginou, se um simples anúncio do google adsense, pudesse controlar a página em que ele foi colocado ? Ele iria alterar o background, trocar titulos na página e bagunçar tudo.

Por isso essa é uma importante funcionalidade nos navegadores, pois evita com que páginas desconhecidas (em domínio diferente) de controlar a página atual em que está visitando.

Com o HTML5, podemos contornar esse problema facilmente. Utilizando o Cross-document messaging, podemos estabelecer comunicação entre páginas e documentos no html, sem se procupar com a origem do domínio. Foi desenvolvido justamente para permitir essa comunicação, sem colocar em risco a segurança da página. (cross-site scripting attacks).

Cross-site messaging funciona apenas no HTML5, e está disponível nas seguintes versões de navegadores:

  • Internet Explorer 8.0+
  • Firefox 3.0+
  • Safari 4.0+
  • Google Chrome 1.0+
  • Opera 9.5+

Vejamos então um exemplo prático:

Digamos que em sua página inicial, você tem o seguinte iframe.

1
<iframe id="exemplo-iframe" src="http://www.exemplo.com/teste.html"></iframe>

Se você quiser mandar o titulo do seu site para o iframe, você precisa usar o cross-document messaging pois ele está em um outro domínio. Veja abaixo como você faria para disparar essa mensagem:

1
2
3
4
<script language="javascript">
var iframe = document.getElementById("exemplo-iframe").contentWindow;
iframe.postMessage("Titulo do Site", "*");
</script>

Na linha 2 é onde obtemos o controle do iframe. Na linha 3 é onde disparamos a mensagem. Note que estamos passando um “*” como segundo argumento do postMessage, o que significa que a mensagem é enviada para todos os domínios. Poderiamos ser mais específicos e disparar apenas para o domínio do iframe (exemplo.com).

Agora, no lado do iframe, só falta receber essa mensagem. Veja abaixo o exemplo do código que o iframe deve carregar:

1
2
3
4
5
6
7
8
<script language="javascript">
function displayMessage(event) {
    var message = event.data;
    alert(message);
    event.source.postMessage("Recebido com sucesso!",  "*");
}
window.addEventListener("message", displayMessage, false);
</script>

Vou começar explicando pela linha 7,  onde é estabelecido o listener, que é responsável por “escutar” as mensagens recebidas e chamar a função displayMessage. Na linha 3, recebemos a mensagem numa variável. Na linha 4 exibimos ela no alert do javascript. Na linha 5, é disparado uma mensagem para o “remetente”, ou seja, podemos enviar uma mensagem para confirmar o recebimento por exemplo.

Lembrando que para que a mensagem enviada na linha 5 seja recebida corretamente pela sua página inicial, você tem que adicionar um listener, da mesma forma que foi feito no iframe. Fazendo assim, é possível fazer trocas de informações entre as páginas de diferentes domínios.

No exemplo acima, qualquer site estaria habilitado em trocar informações com aquela página do iframe (http://www.exemplo.com/teste.html) e dependendo do contexto e de como foi implementado, pode vir a ser uma falha de segurança, portanto, utilize com cuidado.

Google Bookmarks Twitter Yahoo Messenger Orkut Hotmail Google Gmail Delicious Share

Leia também:


[Rafael Biriba] HTML5: Trocando mensagens entre a página e iframes

Saturday, November 27th, 2010

Por questões de segurança e privacidade, os navegadores impedem que haja comunicação entre os conteúdo de diferentes domínios. Ou seja, scripts em diferentes dominios (cross-domain) não podem se interagir.

Na prática seria assim… Já imaginou, se um simples anúncio do google adsense, pudesse controlar a página em que ele foi colocado ? Ele iria alterar o background, trocar titulos na página e bagunçar tudo.

Por isso essa é uma importante funcionalidade nos navegadores, pois evita com que páginas desconhecidas (em domínio diferente) de controlar a página atual em que está visitando.

Com o HTML5, podemos contornar esse problema facilmente. Utilizando o Cross-document messaging, podemos estabelecer comunicação entre páginas e documentos no html, sem se procupar com a origem do domínio. Foi desenvolvido justamente para permitir essa comunicação, sem colocar em risco a segurança da página. (cross-site scripting attacks).

Cross-site messaging funciona apenas no HTML5, e está disponível nas seguintes versões de navegadores:

  • Internet Explorer 8.0+
  • Firefox 3.0+
  • Safari 4.0+
  • Google Chrome 1.0+
  • Opera 9.5+

Vejamos então um exemplo prático:

Digamos que em sua página inicial, você tem o seguinte iframe.

1
<iframe id="exemplo-iframe" src="http://www.exemplo.com/teste.html"></iframe>

Se você quiser mandar o titulo do seu site para o iframe, você precisa usar o cross-document messaging pois ele está em um outro domínio. Veja abaixo como você faria para disparar essa mensagem:

1
2
3
4
<script language="javascript">
var iframe = document.getElementById("exemplo-iframe").contentWindow;
iframe.postMessage("Titulo do Site", "*");
</script>

Na linha 2 é onde obtemos o controle do iframe. Na linha 3 é onde disparamos a mensagem. Note que estamos passando um “*” como segundo argumento do postMessage, o que significa que a mensagem é enviada para todos os domínios. Poderiamos ser mais específicos e disparar apenas para o domínio do iframe (exemplo.com).

Agora, no lado do iframe, só falta receber essa mensagem. Veja abaixo o exemplo do código que o iframe deve carregar:

1
2
3
4
5
6
7
8
<script language="javascript">
function displayMessage(event) {
    var message = event.data;
    alert(message);
    event.source.postMessage("Recebido com sucesso!",  "*");
}
window.addEventListener("message", displayMessage, false);
</script>

Vou começar explicando pela linha 7,  onde é estabelecido o listener, que é responsável por “escutar” as mensagens recebidas e chamar a função displayMessage. Na linha 3, recebemos a mensagem numa variável. Na linha 4 exibimos ela no alert do javascript. Na linha 5, é disparado uma mensagem para o “remetente”, ou seja, podemos enviar uma mensagem para confirmar o recebimento por exemplo.

Lembrando que para que a mensagem enviada na linha 5 seja recebida corretamente pela sua página inicial, você tem que adicionar um listener, da mesma forma que foi feito no iframe. Fazendo assim, é possível fazer trocas de informações entre as páginas de diferentes domínios.

No exemplo acima, qualquer site estaria habilitado em trocar informações com aquela página do iframe (http://www.exemplo.com/teste.html) e dependendo do contexto e de como foi implementado, pode vir a ser uma falha de segurança, portanto, utilize com cuidado.

Google Bookmarks Twitter Yahoo Messenger Orkut Hotmail Google Gmail Delicious Share

Leia também:


[Emerson Macedo] [Caos no Rio - OFF TOPIC] Refletindo sobre valores da vida

Friday, November 26th, 2010

Hoje o Rio de Janeiro viveu um dos capítulos mais feios de sua linda história. Considerada a Cidade Maravilhosa, hoje vimos uma cidade sitiada, com o medo imperando e muita apreensão nas ruas. O motivo de eu escrever esse post sobre o assunto não é diretamente o que aconteceu, mas sim as causas do ocorrido.

A minha história

Pra quem não sabe, eu nasci no suburbio aqui do Rio de Janeiro, mais precisamente no Hospital Albert Swaizer em Realengo e morava num barraco dentro de um beco numa espécie de favela em Padre miguel (atrás da menina de mochila rosa) — As imagens de hoje são muito melhores de quando eu era criança — Lá era uma situação muito difícil, pois a maioria das pessoas era envolvida com alguma coisa errada. Meus Pais se separaram e fui morar na casa dos meus avós com minha tia, que era jovem e trabalhava num emprego modesto. Meu avô trabalhava na companhia de lixo (CONLURB) e minha avó era dona de casa. Essa tia — mãe do coração que me criou — tratou de me tirar daquele ambiente e não mediu esforços para que eu não fosse influenciado por aquele meio. Sempre me deu boa educação (inclusive em casa) e me afastando das amizades erradas. Vários dos meus coleguinhas, que brincavam comigo de bola de gude, pipa, futebol, e outras coisas mais, já morreram ou estão presos. Alguns outros felizmente conseguiram se safar.

Contei essa história apenas pra mostrar que não estou querendo dar uma de entendido, mas eu sei muito bem como funcionam as coias em ambientes desse tipo.

Atacando o problema na Raiz

Após tudo que aconteceu hoje, li muitas mensagens no twitter de manifestação de ódio para com os bandidos, a maioria desejando uma chacina. Veja bem, eu não defendo em hipótese alguma que haja impunidade. Pelo contrário, independente de qualquer coisa, cada cidadão é responsável pelos seus atos e deve responder pelo que faz. O que me incomoda na verdade é que no meu modo de ver as coisas, nossa indignação está sendo direcionada de forma equivocada.

As crianças e a marginalidade

É sabido por todos que cada vez mais os traficantes estão iniciando crianças de 10, 12 anos e por algumas vezes até mais novas para começarem no tráfico. Muitas desssas sequer tiveram a oportunidade de estudar. Muitos bandidos começam oferecendo a essas crianças sexo com mulheres mais velhas, depois drogas e ai a criança já está completamente dominada. Crianças nessa idade ainda não tem a personalidade formada, portanto acho injusto atribuir culpa a uma criança dessas, pois a maioria não tem condições de resistir a esses assédios.

Eu me lembro quando em 2005 eu participada de um trabalho da minha Igreja na favela da coreia, tinha uma criança que aparentava ter uns 8 ou 9 anos de idade, mas já tinha um fuzil pendurado no corpo e ficava sentado numa cadeira de ferro, protegendo o acesso a rua que ficava a casa, onde acontecia a reunião da Igreja. Aquilo sempre me doeu o coração. Era uma situação muito triste. Me lembro que por algumas vezes fui em alguns lugares ali por dentro com meu amigo, que morava e foi criado ali. Geralmente  eu via muitas crianças largadas, sem qualquer assistência, presas fáceis para se tornarem futuros bandidos.

O papel do Estado Brasileiro

Nossos governantes tem falhado miseravelmente há decadas, no que diz respeito a saúde, educação, qualidade de vida, programas sociais, entre outros. O máximo que se vê são os bolsa-isso, bolsa-aquilo, bolsa-etc. Apenas tapando o sol com a peneira.

A cada ano que passa, o ensino público piora mais. Na minha época de infância e adolescência, o nível da escola pública era igual e em alguns casos até melhor que as escolas particulares. Tenho grandes amigos que são testemunha disso. Na geração seguinte a coisa já começou a ficar complicada. Hoje em dia nem se fala.

Sobre a saúde em nem vou perder meu tempo …

Pra piorar, o poder público usa uma estratégia bem conhecida e que sempre deu resultado. Eles criam o problema (falta de condições básicas para todo cidadão), agem em cima do problema (matando) e ainda ganham os aplausos da sociedade (que adora ver bandido morrer), sendo que eles são os principais culpados.

Além disso, não existe no sistema penitênciário brasileiro uma forma de recuperar os bandidos que são presos. É lógico que nem todos querem isso, provavelmente uma minoria, mas certamente é papel do estado oferecer essa oportunidade, até porque não a ofereceu para a maioria dessas pessoas quando ainda eram crianças.

Oportunidade de redenção

É impressionante como nós somos implacáveis com as outras pessoas, mas quando é conosco somos tremendamente generosos. Quando uma pessoa erra, caimos condenando, mas quando erramos sempre temos nossas justificativas e achamos que merecemos outra chance.

Certa vez, assistindo um programa de televisão que debatia o Caso Eloá Cristina, se não me engano o Jornalista Roberto Cabrini, criticando veemente e agredindo com palavras, disse que perguntou ao maniaco do parque: “E se a moça fosse a sua filha?”. Ele recebeu outra pergunta de volta: “E se eu fosse seu filho?”. Cabrini disse que ficou totalmente embaraçado e que isso o fez refletir sobre o quanto agente gosta de pagar o mau com o mau.

Toda pessoa tem direito a uma nova chance. Bandidos deveriam ser presos e deveria existir uma forma de recuperar os que estivessem dispostos a isso (Sinceramente eu não acredio que a pessoa nasça bandido, ou com a índole ruim, etc). Alguns infelizmente não vão querer reabilitação e esses deveriam permancer presos, o que também não acontece, pois após cumprir a pena são soltos, independente de estarem em condições de integrar a sociedade.

Conclusão

Por diversas razões, eu não me surpreendo mais com o desejo de ver sangue que existe em nossa sociedade. Essa falta de amor está prevista na bíblia, meu livro de fé e prática. Sinceramente acho que a tendência infelizmente é piorar, pois o mundo está ficando cada vez mais egoista.

De fato, aqueles que cometem delitos precisam pagar por isso, afinal de contas tudo tem uma consequência. Meu ponto maior é que essas pessoas também são seres humanos e precisam ser tratados como tal. Desejar a morte delas é nos tornar tão ruim ou até pior que essas pessoas.

Hoje em dia vejo muita gente que nunca passou fome na vida ou nasceu em uma família com uma condição boa que olha essas pessoas como se fossem lixo. Não tem a menor noção do que é nascer nessas condições. Por outro lado, vejo pessoas que se gloriam em terem vencido essa situação e crucificam os que não conseguiram. Eu prefiro agradeçer muito a Deus e a minha Tia-Mãe por ter me tirado da convivência e das influências, pois eu poderia ter tido o mesmo destino de alguns coleguinhas de infância, não fossem essas oportunidades.

Indo direto ao ponto, o problema maior está no poder público que não oferece condições básicas iguais para todos os brasileiros. Se fosse assim, ai poderiamos questionar que as escolhas dessas pessoas foram mau feitas. De outra forma, é muita injustiça da nossa parte, principalmente porque a maioria delas foi assediada quando criança.

Pra finalizar, vou falar um pouco do que eu acredito. O mundo tem se esquecido de Deus. Cada vez mais as pessoas só pensam em si próprias, e o exercício do amor ao próximo praticamente não existe.

Então não se esqueça. Somos nós que cuidamos desse mundo. Se ele está assim, cabe a nós muda-lo.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

[Emerson Macedo] Volta das férias, RubyConf Brasil e um pouco de NodeJS

Tuesday, November 23rd, 2010

No final do mês de outubro e no início do mês de novembro tirei um tempo de férias (todo mundo precisa, rs). Nesse tempo eu evitei ao máximo me envolver com trabalho, mas algumas atividades foram inevitáveis até porque já estavam programadas.

Nos dias 26 e 27 de outubro, participei do RubyConf Brasil e apresentei a palestra “Beyond Ruby With NodeJS”, onde basicamente eu falo sobre a repetição do erro em tentar tornar uma tecnologia boa em uma panaceia. Eu sou um rubista convicto e curto muito a tecnologia, mas como já falei tempos atrás aqui mesno nesse blog, não creio ser Ruby/Rails a bala de prata que tanto procuramos (e certamente não acharemos). Os slides seguem abaixo e em breve o vídeo estará disponível no site do evento.

Beyond Ruby with NodeJS – RubyConf Brasil 2010

Passado alguns dias, lancei o segundo episódio do NodeCasts, um site de screencasts em HD sobre NodeJS. O ritmo ainda está um pouco lento, pois a idéia inicial era fazer um screencast a cada 15 dias, mas acabei percebendo que fazer screencasts bem produzidos e com qualidade, sem pausas estranhas e outros detalhes mais que geram um resultado legal da um bocado de trabalho e não é uma tarefa tão simples. Estou aprimorando o processo de produção pra eu poder lançar um a cada 15 dias sem problemas. Se quiser curtir o episódio 2 ou episódio 1 basta clicar no texto linkado. Os screencasts são todos em inglês e colaboradores para tradução são sempre bem vindos e receberão os devidos créditos.

PS: A partir de hoje o blog retorna das férias :)

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

[Bernardo Heynemann] Python Test Spy Engine – MI7

Sunday, November 21st, 2010

Introduction

MI7 is my new pet project. I grew tired of the other mocking/stubbing/spying engines in Python that never did quite what I expected them to.

I’ve been TDDing for a while now in .Net, Ruby, Python and JavaScript. I’ve got my fair share of experience, so I figured I’d give my 2¢ in this issue.

You can check the project at https://github.com/heynemann/mi7/wiki. It’s got a nice tutorial and is currently in 0.1.1 alpha release.

I’ve got a lot of work to do to make it my main tool for test support, but I’m going to get there. Without further delay, let’s get to it.

Why another Spying Engine?

If you check the MI7 wiki you’ll see that I don’t have anything against any single python test support engine. I just haven’t found one that suits my needs and those needs ONLY. IMHO they all do too much. I want a simple, straightforward, fun to use spying engine.

Don’t get me wrong, but I do not believe in mocking in Python. Or stubbing for that matter. Both are akin to dependency injection, IMHO. It just isn’t pythonic.

Python has been around for a while. In this time, there has been a certain Modus Operandi of doing work. This MO has never included injecting your dependencies around. I figured that’s why I feel the weirdness on the part of the mocking/stubbing/spying tools.

With MI7 I’m trying to interfere as less as possible with your code. Production code should be optimized to be production code, and not changed to accommodate your poor testing tools. In the Ruby community they try HARD to make tests and code as clear as possible, not make code work according to tools. I’m trying to get some of that.

The last point of me doing MI7 is to have some fun, and I’m trying to bake in the library as much of that fun as possible, with the spy agency metaphor. Hope you enjoy as much as I am.

Test Sample

Ok, so I’ll write a test with MI7. It’s pretty simple:

from controllers import MyController
from models import User
@new_mission
@agent.spy(User)
def test_user_is_authenticated():
    agents.User.intercept('is_authenticated') \
               .returns(True)
    agents.User.intercept('username') \
               .as_attribute('Bernardo')
    ctrl = MyController()
    result = ctrl.index()
    assert result == "Welcome Bernardo"

So what’s happening here. I’m telling MI7 to keep an eye in the User model, wherever it may be used. Then I’m instructing the User agent (the agents get their code-name from the target they are spying), to intercept calls to is_authenticated and username and return my values.

Now the controller code:

from models import User
class Controller(object):
    def index(self):
        user = User()
        if user.is_authenticated():
            return "Welcome %s" % user.username
        return "Unauthorized"

As you can see, there's not a single line of code in that controller that says "I'm testable". It's just plain old python coding.

Current Status

Currently MI7 supports intercepting modules and classes and telling agents to intercept methods and attributes and to raise exceptions.

Impersonation (stubbing) may come next. Definitely assertions are coming, like what an agent has seen and such.

Conclusion

I’ll keep going with MI7 development as much as I can, because I believe the Python community needs better testing tools and I’m willing to put extra effort into this.

[Rafael Biriba] Net-SFTP: Calculando o progresso do upload

Thursday, November 18th, 2010

Estou escrevendo esse post, para complementar o post sobre o timeout do net-sftp, onde fiquei devendo essa a solução de calculo do progresso…

Para obter o progresso durante o upload, você precisa usar o callback do método upload! e jogar numa variável os valores do tamanho local e do tamanho do arquivo no destino.

Vejamos um pequeno exemplo, retirado da documentação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rubygems'
require 'net/sftp'
Net::SFTP.start('192.168.0.2', 'rafaelbiriba', {:password => 'teste', :timeout => 3}) do |sftp|
  sftp.upload!("/Users/rafaelbiriba/Projects/temp/video-teste-sftp.mp4", "/home/rafaelbiriba/video-teste-sftp.mp4") do |event, uploader, *args|
    case event
    when :open then
      # args[0] : file metadata
      puts "starting upload: #{args[0].local} -> #{args[0].remote} (#{args[0].size} bytes}"
    when :put then
      # args[0] : file metadata
      # args[1] : byte offset in remote file
      # args[2] : data being written (as string)
      puts "writing #{args[2].length} bytes to #{args[0].remote} starting at #{args[1]}"
    when :finish then
      puts "all done!"
    end
  end
end

No exemplo acima podemos verificar:

  • Ao abrir a conexão (when open), podemos chamar args[0].size e obter o tamanho total do arquivo
  • Durante a transferência (when put), ao chamar args[1] podemos obter o tamanho do arquivo remoto

Com isso, quando o tamanho total do arquivo for igual ao tamanho do arquivo remoto, então o upload estará terminado (100%). Para obter as porcentagens, basta fazer o cálculo.

Confira no exemplo abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
require 'rubygems'
require 'net/sftp'
@total_size = 0
@remote_size = 0
@current_progress = 0
 
def update_sftp_progress
  progress = (@remote_size*100)/@total_size)
  if @current_progress < progress then
    @current_progress = progress
    puts "Uploading: #{@current_progress}%"
  end
end
 
Net::SFTP.start('192.168.0.2', 'rafaelbiriba', {:password => 'teste', :timeout => 3}) do |sftp|
 sftp.upload!("/Users/rafaelbiriba/Projects/temp/video-teste-sftp.mp4", "/home/rafaelbiriba/video-teste-sftp.mp4") do |event, uploader, *args|
   case event
     when :open then
       @total_size = args[0].size
       puts "Starting upload..."
     when :put then
       @remote_size = args[1]
       update_sftp_progress
     when :finish then
       puts "Finished!"
     end
   end
end

Toda vez que o arquivo no destino for incrementado, o evento (:put) será disparado, chamando o método update_sftp_progress.

Nesse método é feito o cálculo da porcentagem(ver no exemplo acima). Ao invés de imprimir a porcentagem(com puts), você também pode salvar no banco de dados, ou utilizar o valor para fazer uma barra de progresso.

Espero ter ajudado, ;)

Google Bookmarks Twitter Yahoo Messenger Orkut Hotmail Google Gmail Delicious Share

Leia também:


[Rafael Biriba] Net-SFTP: Calculando o progresso do upload

Thursday, November 18th, 2010

Estou escrevendo esse post, para complementar o post sobre o timeout do net-sftp, onde fiquei devendo essa a solução de calculo do progresso…

Para obter o progresso durante o upload, você precisa usar o callback do método upload! e jogar numa variável os valores do tamanho local e do tamanho do arquivo no destino.

Vejamos um pequeno exemplo, retirado da documentação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rubygems'
require 'net/sftp'
Net::SFTP.start('192.168.0.2', 'rafaelbiriba', {:password => 'teste', :timeout => 3}) do |sftp|
  sftp.upload!("/Users/rafaelbiriba/Projects/temp/video-teste-sftp.mp4", "/home/rafaelbiriba/video-teste-sftp.mp4") do |event, uploader, *args|
    case event
    when :open then
      # args[0] : file metadata
      puts "starting upload: #{args[0].local} -> #{args[0].remote} (#{args[0].size} bytes}"
    when :put then
      # args[0] : file metadata
      # args[1] : byte offset in remote file
      # args[2] : data being written (as string)
      puts "writing #{args[2].length} bytes to #{args[0].remote} starting at #{args[1]}"
    when :finish then
      puts "all done!"
    end
  end
end

No exemplo acima podemos verificar:

  • Ao abrir a conexão (when open), podemos chamar args[0].size e obter o tamanho total do arquivo
  • Durante a transferência (when put), ao chamar args[1] podemos obter o tamanho do arquivo remoto

Com isso, quando o tamanho total do arquivo for igual ao tamanho do arquivo remoto, então o upload estará terminado (100%). Para obter as porcentagens, basta fazer o cálculo.

Confira no exemplo abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
require 'rubygems'
require 'net/sftp'
@total_size = 0
@remote_size = 0
@current_progress = 0
 
def update_sftp_progress
  progress = (@remote_size*100)/@total_size)
  if @current_progress < progress then
    @current_progress = progress
    puts "Uploading: #{@current_progress}%"
  end
end
 
Net::SFTP.start('192.168.0.2', 'rafaelbiriba', {:password => 'teste', :timeout => 3}) do |sftp|
 sftp.upload!("/Users/rafaelbiriba/Projects/temp/video-teste-sftp.mp4", "/home/rafaelbiriba/video-teste-sftp.mp4") do |event, uploader, *args|
   case event
     when :open then
       @total_size = args[0].size
       puts "Starting upload..."
     when :put then
       @remote_size = args[1]
       update_sftp_progress
     when :finish then
       puts "Finished!"
     end
   end
end

Toda vez que o arquivo no destino for incrementado, o evento (:put) será disparado, chamando o método update_sftp_progress.

Nesse método é feito o cálculo da porcentagem(ver no exemplo acima). Ao invés de imprimir a porcentagem(com puts), você também pode salvar no banco de dados, ou utilizar o valor para fazer uma barra de progresso.

Espero ter ajudado, ;)

Google Bookmarks Twitter Yahoo Messenger Orkut Hotmail Google Gmail Delicious Share

Leia também:


[Renan Oliveira] Como melhorar meu resultado de busca usando RDFa ?

Saturday, November 13th, 2010

Anotação semântica

“Esquema específico para geração e uso de metadados, possibilitando novos métodos de acesso a informação”

- Kyriakov, 2003

Nós vivemos procurando formas de melhorar nosso SEO (Search Engine Optimization) para que isso reverta em visitas aos nossos sites,  já algum tempo conheço o RDFa (RDF annotations) que é  uma proposta da W3c para organizar e melhorar o que está escrito em XHTML (Combinando as tags de marcação HTML com regras da XML), deste tempo para cá Google, Yahoo! (leia Search Monkey) aproveitam dessa melhor organização e de novos dados inseridos no XHTML para melhorar a apresentação dos resultados de Busca e melhorando assim o seu ranking já que tal informação está mais clara e objetiva e bem organizada.

Como o google usa o RDFa nos resultados de busca ?

O Google utiliza como padrão para Rich Snippets: RDFa e Microformats.

O Rich Snippets são aqueles resultados diferenciados com Reviews (stars), Events e etc.

Tanto o RDFa quanto o Microformats para o google não faz diferença, ainda. Eu particularmente prefiro o RDFa pois é mantido pelo pessoal da W3 Semantic Web Group.

Exemplos de uso em filmes (IMDb):

O próprio Google da dicas de como usa, segue os links:

Como marcar conteúdo usando RDFa:
http://www.google.com/support/webmasters/bin/answer.py?hl=br&answer=146898

Introducing Rich Snippets: http://googlewebmastercentral.blogspot.com/2009/05/introducing-rich-snippets.html

E agora, o Yahoo! usa o RDFa nos resultados de busca ?

Originalmente, a mesma anotação em RDFa será apresentada de forma parecida tanto no Google, quanto no Yahoo! sendo que no Yahoo a aplicação é um pouco mais vasta como pode ser vista nos links abaixo.

O Yahoo! (Search Monkey) participa de um excelente projeto para organizar os dados com Web Semântica (RDFa), o Projeto Commom Tag.

Exemplos de uso em Eventos:

Excelente explicação de como o Yahoo! captura e utiliza os dados em RDFa, além um ótimo tutorial:

http://developer.search.yahoo.com/start

E como usar essa anotações no Meu Blog? Use o  Zemanta

O Projeto Zemanta começou como um Plugin para o Firefox e com o passar do tempo se tornou um Plugin para Blogs e hoje já é recomendado inclusive pelo WordPress, veja o post.

O Zemanta, funciona com um plugin que sugere notícias relacionadas, links , fotos e tags para organizar o seu conteúdo.  Nessas tags que moram a grande sacada do Zemanta, ele escreve essas informação em RDFa.

Nesse post e nos futuros pretendo continuar usando o Zemanta para anotar os meus conteúdos, falo isso pois a Semantic Web continua crescendo de forma exponencial e poderá surgir um melhor “anotador” , por agora estou muito satisfeito com o uso do mesmo. Você pode ver aqui quais informações o Zemanta nos sugere, Exemplos de Uso.

Existem projetos, bem interessantes, que utilizam o RDFa como padrão:
Facebook – http://rdfa.info/2010/04/22/facebook-adopts-rdfa/
Best Buy – http://www.readwriteweb.com/archives/how_best_buy_is_using_the_semantic_web.php
Newsweek… Drupal….O’relly..

Caso queira saber mais informações, recomendo esses links:

http://www.slideshare.net/lzomatos/anotao-semntica-de-contedo-web-utilizando-microformatos-e-rdfa (PT-Br)

http://www.w3.org/TR/xhtml-rdfa-primer/ (Inglês)

http://www.alistapart.com/articles/introduction-to-rdfa/ (Inglês)

http://ilrt.org/discovery/2001/04/annotations/ (Inglês)

RDFa Basics

[Rafael Carício] Cookie SQL Injection - Explorando uma falha de segurança na prática

Sunday, November 7th, 2010

Quando converso com desenvolvedores Web eu percebo que são poucos que têm conhecimento de programação segura para Web. A algum tempo atrás eu trabalhava com Java e tinha/tenho muita preocupação com a questão de segurança. Cheguei até a tentar lecionar um curso de programação segura para Web em Java na uCon Security Conference, porém devido a falta de interesse o curso acabou não acontecendo. Acredito que conhecer, no mínimo, as formas de ataques mais básicas é fundamental para qualquer desenvolvedor Web. Um bom lugar para começar é conhecendo o projeto o Open Web Application Security Project (OWASP). Lá vocês podem encontrar uma vasta gama de informações sobre segurança na Web. Um sub-projeto interessante do OWASP é o que lista as 10 vulnerabilidades mais encontradas na Web.

Como mencionei no post anterior, o código em C que postei para melhorar a performance no acesso de aplicações Django usando o NGINX e Memcached tem uma falha de segurança que permite ataques de SQL Injection. Inicialmente eu pensei em realizar a correção no código e depois postar no blog. Mas depois me ocorreu que eu poderia mostrar como explorar esta falha. Achei que isso poderia ser bastante interessante para vocês verem como funciona esse tipo de ataque.

Bem, olhando o código escrito em C talvez não seja tão evidente a existência da falha. Pois normalmente os ataques de SQL Injection teem uma forma de entrada do código malicioso e saída da informação recolhida dentro do sistema. Normalmente esse problema é encontrado em aplicações Web onde é verificada a informação retornada em algum campo que é apresentado dentro do código HTML. Mas as falhas e aplicações se comportam totalmente diferentes em sistemas diferentes. A criatividade deve entrar em ação para tentar descobrir como interferir no sistema e obter uma resposta com sucesso. Ao analisar o comportamento da aplicação em funcionamento aparentemente não encontramos nenhuma forma de obter um retorno sobre qual o dado que está armazenado. O que conhecemos é o comportamento do sistema. Quando um visitante acessa a aplicação ele pode obter uma resposta da aplicação Web em Django ou do código em C onde existe a evidência de falha. Então sabemos que nossa atenção deve ser em cima de como fazer a requisição ir para o código vulnerável. Assim, lembrando do post anterior, todas as requisições passam pelo código em C onde é feita uma consulta a base de dados pelos dados existentes na sessão do usuário que no Django (e na maioria, se não, todos os tipos de aplicações web) armazena o Session Key no cookie do browser do usuário. O código realiza uma consulta a base de dados sobre a sessão e verifica o tamanho desses dados, caso seja maior que 60 caracteres (que foi o tamanho máximo identificado por mim para uma sessão de usuário não autenticado) a requisição é repassada para o Django e é entendido que o usuário está autenticado. Caso contrário, o usuário não está autenticado e a requisição é retornada a partir dos dados existentes no Memcached. Analisando esse fluxo, podemos perceber que a chave para o ataque é identificar como saber se a requisição vem do código em C ou do Django. E usar isso para obter uma resposta, já que este SQL executado (e que contém a vulnerabilidade) só é usado para isso. Assim procurei e achei a diferença entre as respostas do Django e do código vulnerável. Quando a resposta vem do Django, existe uma variável que aparece no cabeçalho da resposta a requisição HTTP. Ao descobrir isso, eu já sabia quando uma requisição vinha do Django e quando vinha do código em C e sabia que se o resultado retornado depois da execução do código SQL se fosse maior que 60 ele ia passar pra o Django e caso fosse menor ele mesmo iria responder. Assim, eu agora precisava só descobri como usar isso para obter informações sobre o sistema, no caso, informações importantes armazenadas na base de dados.

Primeiro eu precisava escolher que informação eu iria tentar obter, dentro do contexto teria que ser algo que estivesse no banco de dados da aplicação. Eu sei que toda aplicação Django com autenticação tem uma tabela chamada auth_user onde ficam armazenados os usuários, então escolhi atacar essa tabela e obter informações sobre os usuários da aplicação.

Bem, depois de descobrir onde deveria atacar eu precisei imaginar (usar a criatividade para) pensar em como fazer a resposta da execução do SQL ser maior que 60 caso a condição que eu verificasse fosse verdadeira ou falsa. Assim eu poderia usar a informação que a resposta veio do Django ou não para validar o que eu estaria perguntando ao banco de dados.

OFF-Topic: Resolvi ir tomar um banho e ficar pensando sobre como fazer isso. Minhas idéias fluem quando estou tomando banho e é lá onde eu tenho muitas ideias interessantes. Acho que quase todas que já postei ou vou postar neste blog surgiram quando eu estava tomando banho.

No final de todo o processo de pensar testar a avaliar o funcionamento eu escrevi este código. A ideia dele é fazer uma requisição a aplicação usando cada letra do alfabeto ou caractere válido para o campo que eu queria e fazer com que a resposta vá para o Django sempre que eu achar o caractere certo. Assim eu teria que iterar caractere por caractere para descobrir um-por-um. E foi isso que eu fiz.

Este código varre todas as possibilidades sobre cada caractere e vai validando cada entrada. No final podemos obter o nome de um usuário que é staff do sistema. Este mesmo código, sem muitas modificações pode ser usado para obter muitas outras informações. Ai vale a criatividade de cada um. Isso é apenas um exemplo simples.

A criatividade é um fator fundamental a qualquer pessoa que deseja realizar um ataque. Pois cada ataque requer um cuidado ou ação bem especifica. Cada sistema tem um funcionamento e foi implementado de uma forma totalmente diferente. Por isso que dificilmente um ataque que obteve sucesso sobre um sistema vai obter o mesmo sucesso sobre outro. O importante na questão de segurança é entender o fundamento do ataque e não decorar como foi feito. O fato da forma de atacar cada sistema ser diferente leva a que poucas pessoas realizem ou tenham sucesso ao tentar realizar esse tipo de atividade.

Espero que tenham gostado do post e ainda tenho muitas ideias que não postei aqui. Muita coisa ainda está por vir. A interação de vocês por meio de comentários é muito importante para minha motivação a continuar postando coisas aqui. Por isso, escrevam suas opniões, criticas ou elogios tudo isso é sempre bem-vindo.

[Rafael Carício] Deployment de Django usando NGINX, Memcached e um pouco de código em C

Friday, November 5th, 2010
Depois do post anterior eu começei a pensar em como eu poderia melhorar ainda mais a performance da nossa aplicação Django. Então tive a ideia de fazer cache das páginas estáticas e servi-las direto do memcached para o usuário. Isso funcionou muito bem, mas existe um problema quando essa mesma ideia é aplicada a uma aplicação onde os usuários realizam login e precisam acessar páginas personalizadas com coisas do tipo “Olá {{ nome_do_usuario }}, bem-vindo!”. E pensei bastante sobre isso e deixei pra resolver este problema depois. Resolvi atacar inicialmente os visitantes externos, que não são usuários do sistema consequentemente que não estão autenticados no sistema. Neste grupo de visitantes se encontram também os engines de pesquisa como Google, Yahoo!, Bing e etc. E também os navegantes de primeira viagem que chegaram no site. Assim, quanto melhor a experiência que estes visitantes tiverem no primeiro acesso ao site maior as chances deles voltares ou se cadastrarem para usar o sistema. A velocidade de carregamento das páginas do site é um dos criterios de qualidade que estes visitantes analisam para decidirem se voltam ou não. Inclusive o Google recentemente anunciou que vai usar/usa o tempo de carregamento como critério no seu algoritmo de PageRank, ou seja, mais um motivo para motivar a desbravar esta ideia.

Para deixar o acesso dos visitantes não autenticados mais rápido não precisamos pensar muito, se você leu o post anterior e fez um teste simples deve ter percebido os ganhos em velocidade que foram extremamente absurdos. Assim, precisamos enviar esses visitantes não autenticados para o memcached diretamente sem que a requisição passe pela stack do Python / Django. Dessa forma desafogamos um pouco (ou muito) nossa aplicação pois ela só vai processar requisições que são realmente interessantes e que precisam de um processamento mais dinâmico. Se pararmos pra pensar, percebemos que os visitantes não precisam acessar as páginas com dados atualizando em tempo real (depende muito da aplicação, mas de um modo geral isso é verdade). Por exemplo, se nossa aplicação tem um forúm os visitantes do site não precisam ver o forúm se atualizando a cada acesso ou a cada segundo que ele visita o site. Já os usuários autenticados, precisam e devem ver o forúm atualizado o mais rápido possível para que eles possam interagir com os outros usuários do site. E essa ideia é aplicada a todas as páginas externas do site pois nem os engines de pesquisa ficam acessando o site a cada milisegundo pra ver o que mudou. Resumindo, os visitantes do site não precisam ver as coisas atualizadas eles provávelmente estão entrando no site pela primeira vez e tudo pra eles é novidade.

Agora que decidimos que precisamos fazer cache de tudo que é acessado por usuários não autenticados ficou fácil, não é? Não, como vamos saber quando o usuário está autenticado ou não? No código Python / Django podemos descobrir isso fácil mas como descobrir isso antes da requisição chegar ao Python? Precisamos validar se o usuário está autenticado ou não o mais rápido possível e enviar a resposta pra ele. O ideal é descobrir isso diretamente no NGINX, mas não tem uma forma de fazer isso. Inicialmente eu pensei em validar a existência do cookie do Django nas requisições e se ele existisse o usuário estaria autenticado. Porém isso não funciona pois o Django cria um cookie de sessão mesmo se o usuário não for autenticado. Sendo assim, o que fazer? Essa foi minha dúvida e decidi estudar o código do Django nessa parte de autenticação e gerenciamento de sessão para saber o que eu preciso fazer pra descobrir se o usuário está autenticado ou não. Depois de fazer isso, resumindo, cheguei a conclusão que não dava pra deserializar o objeto pickler que o Django salva no BD pra descobrir se o usuário está autenticado ou não. Então, analisando o comportamento do cookie do Django eu percebi que dava pra fazer uma validação simples, que não dá 100% de acerto sobre a questão do usuário estar autenticado ou não, mas já é uma boa (do meu ponto de vista). Eu descobri que posso validar o tamanho dos dados da sessão, não dá pra deserializar o objeto da sessão, mas dá pra validar o tamanho da string salva no BD. E é assim que eu faço a validação pra saber se o usuário está autenticado. Se os dados da sessão forem maior que um limite mínimo, quer dizer que o usuário está autenticado. No meu caso isso funciona pra mim porquê eu não salvo nada na sessão quando o usuário não está autenticado (é importante essa informação). Se você salva algo na sessão do usuário em páginas públicas da sua aplicação esse esquema, do jeito que eu faço agora, pode não funcionar pra você.

Resolvido esses problemas, eu tentei resolver o problema de acessar o banco de dados para pegar os dados que estão armazenados na sessão do usuário e validar se ele está autenticado antes da requisição ir para o Django. Essa validação tinha que ser feita no próprio NGINX ou em alguma coisa bastante rápida pra conseguir obter essa resposta. Então procurei várias alternativas. Primeiro eu pensei em usar node.js, mas cai no problema que eu ainda não conheço a tecnologia direito e então isso poderia ser um problema. Tentei procurar outra coisa, um modulo para o NGINX, talvez. Até achei um módulo que dá pra usar código em Lua no NGINX, mas eu também tinha que aprender Lua e não me pareceu necessário nesse momento também. Tentei achar uma outra solução e foi ai que achei um post em um blog mostrando um exemplo de consulta ao memcached usando código em C. Entao me ocorreu que eu poderia modificar esse código para atender as minhas necessidades. E foi isso que eu fiz. Código em C é o mais rápido que eu poderia conseguir (tá, eu sei… mas eu não sei Assembly tão bem assim, ainda).

Para explicar a ideia que eu tive, eu criei alguns diagramas de sequencia pra ficar mais fácil de entender. Abaixo eu mostro a primeira situação. Nesse caso eu mostro o que acontece quando o usuário acessa a aplicação e não está autenticado. Eu chamo o meu código em C de UserRouter, ele valida se o usuário está autenticado e se não estiver ele consulta no memcached a página que o usuário está tentando acessar e envia de volta para o NGINX no caso da página existir no memcached. Caso a página não exista ele envia a requisição para o Django normalmente.

arquitetura

No segundo cenário eu quero mostrar o que acontece quando um usuário autenticado acessa a página ou quando não existe uma página pública ainda em cache.

sem dados

A parte que coloca a página no memcached é opcional, pois se for uma página interna da aplicação ou uma página que apenas usuários autenticados acessam, ele nunca vai pra o memcached.
Então, para suportar esse funcionamento eu reusei o middleware do post anterior.

Adicionei algumas configurações ao settings.py:

E o código em C que faz toda essa mágica acontecer.

PS.: Bem, eu só vou avisando logo que esse código em C tem uma falha de SQL Injection que eu ainda vou corrigir (e atualizo aqui pra vocês).
Pra compilar esse código vocês teem que instalar algumas bibliotecas, mas essa parte é fácil se você usa o ubuntu.

rafaelcaricio@ubuntu:~/development$ sudo apt-get install libmysqlclient-dev libevent-dev libmemcached-dev

E pra compilar o código. A linha de comando é:

rafaelcaricio@ubuntu:~/development$ gcc -o v_auth_and_cache -levent -I/usr/include/mysql  -DBIG_JOINS=1  -fno-strict-aliasing   -DUNIV_LINUX -DUNIV_LINUX verify_auth_and_cache.c -Wl,-Bsymbolic-functions -rdynamic -L/usr/lib/mysql -lmysqlclient -lmemcached

Depois é só executar o servidor UserRouter colocando na porta 8000. Usando essa linha de comando:
rafaelcaricio@ubuntu:~/development$ ./v_auth_and_cache localhost 8000

E fazer algumas alterações na configuração no NGINX. Assim a requisição sempre vai primeiro pra o UserRouter e depois, se for o caso, passa para o Django.


No final eu realizei bastante testes e verifiquei que tudo isso realmente funciona e deixa o acesso a páginas externas extremamente rápido. Certo que eu ainda vou testar muito isso e melhorar esse funcionamento para poder usar no AtéPassar. Mas tenho certeza que isso vai melhorar bastante a velocidade de indexação pelos engines de busca e melhorar também a experiência dos usuários que estão acessando o site pela primeira vez. Eles vão ver tudo funcionando incrivelmente rápido. Espero ter ajudado ou aberto a mente de alguns de vocês para novas possibilidades. Em breve estarei escrevendo mais um post sobre outra ideia ou sobre alguma outra coisa que eu já fiz nas minhas horas vagas. Abraços e até logo.