Usando OAuth com o Twitter em Cocoa/Objective-C
Ultimamente o OAuth tem se tornado bastante popular. Diversos websites o estão adotando como o mecanismo principal de autenticação para suas APIs, e a maioria deles como o único. Então o que exatamente é OAuth, e o que ele faz? De acordo com o site oficial (em inglês):
This is what OAuth does, it allows the you the User to grant access to your private resources on one site (which is called the Service Provider), to another site (called Consumer, not to be confused with you, the User). While OpenID is all about using a single identity to sign into many sites, OAuth is about giving access to your stuff without sharing your identity at all (or its secret parts).
Basicamente, OAuth é uma forma de se autenticar em um serviço web sem precisar guardar a senha do usuário, e na maioria dos casos sem nem mesmo precisar usá-la. O Twitter adotou o OAuth para autenticação, e a partir de 16 de Agosto, será a única forma de se usar sua API. Neste post eu irei explicar como usar OAuth para se autenticar no Twitter em Cocoa/Objective-C.
Escolhendo o método de autenticação
O Twitter nos oferece três formas de autenticação usando OAuth. A primeira, mais usada em aplicativos web, é enviar uma URL de callback (retorno) em sua requisição, assim após o usuário autorizar seu aplicativo ele será redirecionado para esta URL de callback e seu app pode continuar daí. A segunda, direcionada para aplicativos desktop e móveis, é usar a chamada autenticação "out-of-band": após a autorização, o Twitter fornece ao usuário um código PIN que ele poderá digitar em seu app para continuar. E a terceira é enviar o login e a senha do usuário através de xAuth. Apesar desta parecer a forma mais simples de usar, o Twitter a considera a forma menos desejada (já que o usuário continua precisando digitar sua senha no aplicativo), e para usá-la você precisa pedir permissão diretamente para o Twitter, enviando detalhes sobre seu app e o motivo de você querer usá-la para api@twitter.com. Neste guia nós usaremos o método de autenticação por código PIN (out-of-band), já que este método não requer que você configure uma URL de callback nem precisa de permissão do Twitter.
Primeiros Passos
Antes de mais nada, se você ainda não o fez, vá para a Plataforma de Aplicativos do Twitter e registre seu app para usar OAuth (sim, você pode registrar um app de testes, não há necessidade de aprovação). Depois de registrá-lo, anote o Consumer Key e o Consumer Secret que o Twitter atribuirá ao seu app, já que você vai precisar deles em alguns instantes.
Neste exemplo, eu estou usando o OAuthConsumer para gerenciar as requisições OAuth. Existem duas versões disponíveis, e a que eu usei no link foi modificada para suportar o código PIN do Twitter. Mas cuidado, há um bug em seu código: na linha 214 do OAMutableURLRequest.m, o código correto deve ser:
if (token.verifier != nil && ![token.verifier isEqualToString:@""]) {
Eu pretendo enviar esta correção para o autor, mas no momento você pode apenas corrigir manualmente ou então usar a versão que está junto com o código-fonte do meu projeto, que você pode baixar no final deste post. Eu levei horas pra descobrir este minúsculo bug.
Update: graças ao Raphael Caixeta, eu percebi que havia linkado para a versão errada do OAuthConsumer (existem vários forks diferentes). Ele gentilmente criou um arquivo ZIP contendo a versão correta, e você pode baixá-lo aqui.
A autenticação do Twitter via OAuth (usando um código PIN) é um processo de três passos. Primeiro você pede um Request Token, em seguida você redireciona seu usuário para uma página onde ele pode autorizar seu app e pegar o código PIN, então finalmente você pede um Access Token. Depois disso você só precisa usar esse Access Token para assinar todas as requisições que seu app fizer.
Request Token
Menos conversa, mais código. Vamos lá:
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY" secret:@"CONSUMER_SECRET"]; OADataFetcher *fetcher = [[OADataFetcher alloc] init]; NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"]; OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url consumer:consumer token:nil realm:nil signatureProvider:nil]; [request setHTTPMethod:@"POST"]; [fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(requestTokenTicket:didFinishWithData:) didFailSelector:@selector(requestTokenTicket:didFailWithError:)];
Primeiro nós criamos um objeto OAConsumer, usando a Consumer Key e a Consumer Secret que o Twitter nos forneceu (não se esqueça de trocar CONSUMER_KEY e CONSUMER_SECRET no código por suas chaves). Daí nós criamos um objeto OAMutableURLRequest usando este consumer e a URL de Request Token do Twitter. Nós configuramos a requisição para usar HTTP POST e finalmente usamos um OADataFetcher para enviá-la. Esta chamada usa dois métodos delegate para sucesso e falha. Este é o código para o método de sucesso:
- (void) requestTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { if (ticket.didSucceed) { NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody]; NSString *address = [NSString stringWithFormat: @"https://api.twitter.com/oauth/authorize?oauth_token=%@", accessToken.key]; NSURL *url = [NSURL URLWithString:address]; [[NSWorkspace sharedWorkspace] openURL:url]; } }
Neste método nós pegamos o corpo da resposta e usamos o método initWithHTTPResponseBody da classe OAToken para criar o nosso Request Token. Então nós usamos a chave deste token e redirecionamos o usuário para uma página do Twitter onde ele pode autorizar nosso app e pegar o código PIN. Esta é a página que será exibida ao usuário:
Depois que o usuário autorizar nosso app, o Twitter irá exibir um código PIN (com 7 dígitos) que o usuário deve anotar ou copiar. Nós usaremos este código PIN no próximo passo.
Access Token
Para pegar o Access Token o código é bem semelhante:
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY" secret:@"CONSUMER_SECRET"]; OADataFetcher *fetcher = [[OADataFetcher alloc] init]; NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"]; [accessToken setVerifier:@"PIN_CODE"]; OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url consumer:consumer token:accessToken realm:nil signatureProvider:nil]; [request setHTTPMethod:@"POST"]; [fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(accessTokenTicket:didFinishWithData:) didFailSelector:@selector(accessTokenTicket:didFailWithError:)];
Agora nós usamos o código PIN como verifier em nosso token. Em seguida nós enviamos o token que obtivemos antes (agora incluindo o código PIN) em nossa requisição. Todo o resto é praticamente igual ao passo anterior. Este é o novo método delegate para sucesso:
- (void) accessTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { if (ticket.didSucceed) { NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody]; } }
Fácil, não? Nós apenas pegamos o corpo da resposta e recriamos nosso token usando os novos dados. Este novo token é tudo que nós precisamos para assinar nossas requisições daqui pra frente. Desde que você mantenha este token, você provavelmente nunca mais vai precisar autorizar seu app de novo. A classe OAToken possui métodos para guardar e recuperar este token, assim você pode mantê-lo após finalizar seu app e iniciá-lo novamente.
Agora você já pode usar qualquer método da API do Twitter que quiser. Segue abaixo um exemplo de como obter a timeline do usuário:
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY" secret:@"CONSUMER_SECRET"]; OADataFetcher *fetcher = [[OADataFetcher alloc] init]; NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.xml"]; OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url consumer:consumer token:accessToken realm:nil signatureProvider:nil]; [fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(apiTicket:didFinishWithData:) didFailSelector:@selector(apiTicket:didFailWithError:)];
Projeto de Exemplo
Como você provavelmente percebeu, este post contém apenas o código diretamente relacionado com o que eu estava tentando explicar. Se você quiser o código completo (incluindo meu OAuthConsumer modificado) eu criei um projeto de exemplo que inclui todos os métodos que eu usei aqui e uma interface básica contendo botões para chamar cada método (além de campos para a consumer key, consumer secret e o código PIN).
Este projeto requer o Mac OS X 10.5 (Leopard).
Usando (e compartilhando) uma conexão VPN no seu Mac
Antes de mais nada, desculpem-me pela falta de posts, eu ando meio ocupado ultimamente. Eu finalmente atualizei minha máquina de desenvolvimento para o Snow Leopard (eu estava no Leopard 10.5.7) e aproveitei a oportunidade para organizar todos os meus backups, documentos e afins. Eu ainda não terminei de acertar todas as minhas rotinas de backup, mas pelo menos já estou coberto em caso de uma pane (depois do incidente dos capacitores, eu decidi levar meus backups mais a sério).
Enfim, uma das coisas que eu sempre quis (e finalmente tive tempo de) fazer era configurar meu próprio servidor OpenVPN. Caso você não saiba, VPN significa "Rede Particular Virtual", e é uma forma de você ter sua própria rede segura, não importa onde você esteja. Quando você estiver em um café ou em um hotel e quiser ter certeza que ninguém vai espiar o que você está fazendo (sim, isso é bem fácil de fazer) você precisa de uma VPN. Ter um servidor VPN também pode te ajudar a contornar o infame geoblocking, se é isso que você pretende.
Eu decidi escrever este artigo para dividir com vocês a experiência que eu tive configurando minha própria VPN, especialmente quando eu precisei compartilhar a conexão com outros dispositivos na minha rede. Se é isso que você quer fazer, continue lendo e eu vou tentar explicar o que eu fiz.
O Servidor
Se você quer ter sua própria VPN, a primeira coisa que você precisa é de um servidor OpenVPN. Você tem duas opções: usar seu próprio servidor ou usar um provedor de serviços OpenVPN. O processo de configurar seu servidor sai um pouco do escopo deste artigo, mas se você tem um servidor Linux você pode encontrar ótimos guias na biblioteca da Linode. Aliás, a Linode é uma ótima empresa se serviços VPS (e eu recomendo - este servidor está localizado lá). Inclusive se você quiser ter seu próprio servidor lá você pode usar meu código de afiliado.
Outra opção é usar um provedor de serviços VPN. Existem servidores VPN gratuitos ou pagos, e se tudo o que você quer é ter uma VPN sem se preocupar em configurar um servidor, este é o caminho mais fácil. Aqui tem uma lista de provedores de serviço VPN (os preços vão de 0 a R$ 30 por mês, dependendo da velocidade/banda que você precisa).
O Cliente
Ok, então você já tem seu servidor, agora você precisa de um cliente para conectar à sua VPN. Eu vou te ajudar a configurar o Tunnelblick no Mac OS X. Como eu nunca usei um cliente OpenVPN no Windows eu não posso te ajudar neste caso, mas se você estiver usando Windows eu posso te recomendar o OpenVPN GUI.
A primeira vez que você abrir o Tunnelblick depois de instalá-lo ele vai pedir sua senha. Tudo bem, ele precisa dela para garantir a segurança das suas chaves e configurações (o que é muito importante, já que qualquer um com acesso às suas chaves pode se conectar no seu servidor VPN). Depois disso, ele vai perguntar se você deseja criar um arquivo de configuração básico. Eu imagino que você já tenha seus arquivos de configuração e certificados (a criação deles é parte da configuração do servidor) então vamos apenas pedir que ele abra a pasta de configurações, para que a gente possa colocar nossos arquivos lá. Se você não tiver um arquivo de configuração do seu servidor, você pode então deixar o Tunnelblick criar um para você. Feche o programa depois disso.
Copie seus arquivos de configuração e certificados para a pasta de configurações. Normalmente você vai precisar copiar 4 arquivos: client.conf, ca.crt, <seucliente>.crt e <seucliente>.key. Renomeie o client.conf para o nome que você quiser usar para identificar seu servidor (por exemplo MyServer.conf), abra-o no seu editor de textos favorito e verifique se ele já possui pelo menos as linhas abaixo (deixe todas as outras como estão):
remote <endereco do seu servidor> <porta do seu servidor> ca ca.crt cert <seucliente>.crt key <seucliente>.key
Salve seus arquivos e abra o Tunnelblick novamente. Ele vai adicionar um ícone semelhante a um túnel preto na sua barra de menus. É lá que ele fica quando está rodando, para que você possa conectar ao seu servidor OpenVPN rapidamente sempre que quiser. Se você clicar neste ícone, você vai ver uma opção para conectar em seu servidor, com o mesmo nome que você usou no arquivo de configurações. Mas antes de conectar, vamos verificar qual é seu endereço de IP externo no momento: entre neste site, procure por seu IP e anote-o.
Pronto para se conectar? Clique no ícone do Tunnelblick e selecione Connect 'YourServer'. Ele vai tentar se conectar ao seu servidor VPN (se ele pedir sua senha novamente não tem nada de errado, ele está simplesmente protegendo os arquivos que você editou. Ele não vai pedir sua senha toda vez). O ícone do menu será animado enquanto ele estiver conectando, e se ele se conectar com sucesso o ícone vai se transformar em um túnel aberto. Clique no ícone do menu novamente e a primeira linha do menu deve ser Tunnelblick: 1 connection active. Volte para este site e verifique seu IP novamente. Se ele mudou então parabéns, você já está usando sua conexão VPN e todo o seu tráfego está agora passando por uma conexão segura.
Se algo deu errado e sua conexão VPN não está funcionando, abra o menu do Tunnelblick novamente e selecione Details. Ele irá mostrar um arquivo de log bem detalhado, e lá você pode verificar se ocorreu algum erro. E se você conseguiu se conectar ao servidor VPN mas seu IP não mudou, o problema é provavelmente no servidor: ele precisa estar configurado para encaminhar todo o tráfego VPN e para ser o gateway padrão do cliente. Todas estas opções são explicadas no guia da Linode que eu mencionei. Claro, se você estiver usando um provedor de serviço VPN você também pode entrar em contato com o suporte.
Compartilhando a Conexão VPN
Então agora você está conectado ao seu servidor e a sua conexão está sendo roteada de forma segura pela VPN (vai lá e testa o Hulu, eu espero. Eu sei que você quer tentar). Mas e se você quiser usar a mesma VPN em outros dispositivos na sua rede? Claro, você pode configurar o Tunnelblick em mais de um Mac, mas alguns dispositivos como o iPhone ou o XBOX 360 não possuem clientes OpenVPN. O que fazer nesse caso?
A solução que eu encontrei é simples: você pode compartilhar a conexão VPN do seu Mac e então usar seu Mac como um gateway para os outros dispositivos. O problema é que o recurso Internet Sharing do OSX não parece gostar muito do OpenVPN. Eu tentei usá-lo de todas as formas possíveis, mas não consegui. Então eu pesquisei um pouco como o Internet Sharing funciona e encontrei uma solução que não é tão simples, mas uma vez configurada funciona perfeitamente.
Abra seu editor de textos favorito e crie um novo arquivo. Cole as seguintes linhas nele:
#!/bin/sh natd -interface tun0 ipfw -f flush ipfw add divert natd ip from any to any via tun0 ipfw add pass all from any to any sysctl -w net.inet.ip.forwarding=1
Salve o arquivo com um nome como natvpn.sh. Clique com o botão direito no arquivo no Finder, selecione Get Info e dentro de Permissions marque Execute. Feche a janela do Get Info.
Ok, o que diabos foi isso que eu fiz acima? Deixe-me tentar explicar com calma. Nós estamos usando alguns comandos para permitir que seu Mac se torne um gateway e passe a encaminhar todos os dados que ele receber para a conexão VPN. Isso é muito semelhante ao que o Internet Sharing faz de forma transparente. O nome tun0 é o nome padrão da interface de rede que o Tunnelblick cria para a sua VPN, e isso você pode confirmar abrindo o Terminal e digitando ifconfig enquanto conectado à sua VPN.
Abra o Terminal. Se você não estiver conectado à VPN, conecte-se agora. Vá para o diretório em que você salvou o arquivo (se você o salvou na sua pasta home, você já está lá) e digite:
sudo ./natvpn.sh
Você deve trocar natvpn.sh pelo nome que você usou para salvar seu arquivo acima. Ele vai pedir sua senha, digite-a e você verá algo semelhante a isso:
Flushed all rules. 00100 divert 8668 ip from any to any via tun0 00200 allow ip from any to any net.inet.ip.forwarding: 0 -> 1
Funcionou: seu Mac já se tornou um gateway! Agora tudo que você precisa fazer é pegar o dispositivo que você quer usar na VPN e, dentro de suas configurações de rede, alterar o gateway padrão para o IP do seu Mac. Na maioria dos dispositivos, para alterar o gateway padrão você também precisará o configurar para usar IP estático (meu iPhone, por exemplo, precisou). Copie o mesmo IP, subnet mask e DNS server que ele já estiver usando e mude apenas o gateway para o IP do seu Mac. Ah, e se você não sabe qual é o IP do seu Mac vá em Preferências, abra Network (ou Rede) e selecione sua conexão de rede local. No painel à direita ele vai te mostrar o IP abaixo de Status.
Teste seu dispositivo indo ao mesmo site de antes e ele deve mostrar o endereço IP do seu servidor. Parabéns e aproveite sua nova VPN!
Conclusão
Como você pode ver, configurar uma conexão VPN é relativamente simples. Compartilhá-la pode até ser um pouco mais complicado, mas agora que já está tudo configurado tudo que você precisa fazer é abrir o Terminal e digitar sudo ./natvpn.sh enquanto estiver conectado à VPN, toda vez que você quiser compartilhá-la. Não é automático, mas funciona muito bem. E claro, se tudo que você quer é usar a VPN no seu Mac, então você só precisa se conectar usando o Tunnelblick e pronto.
Este guia assume que você tem ao menos um pouco de experiência usando o terminal. Se você não tem, talvez se sinta meio perdido em algumas partes, principalmente se você tentar compartilhar sua conexão VPN. Se este for seu caso, sinta-se à vontade para deixar um comentário abaixo e eu prometo que tentarei te ajudar!
O Dia Que Minha Placa de Vídeo Explodiu
Ok, talvez eu tenha exagerado um pouco. Minha placa de vídeo não explodiu literalmente. O que aconteceu foi o seguinte:
Ontem eu estava trabalhando quando meu computador travou. "Bom, às vezes acontece", eu pensei, e tentei reiniciá-lo. Ele aparentou iniciar normalmente, mas foi só por uns segundos. O Mac OS simplesmente travava no login, e quando eu tentei iniciar o Windows deu tela azul. Eu até consegui iniciar o OSX em modo de segurança e tudo parecia estar normal: os HDs estavam funcionando, os programas rodavam normalmente, nenhum erro. Então eu desliguei o computador e tentei ligar de novo 10 minutos depois. Isso foi o que apareceu:

Bom, talvez meu monitor esteja fora de sintonia...
"Só pode ser algo na placa de vídeo", eu pensei. Abri meu computador, tirei fora a placa de vídeo e comecei a inspecioná-la. Rapidamente encontrei os culpados:

Isso mesmo: três belos capacitores queimados.
Inicialmente eu entrei em pânico. Este é meu computador de trabalho, eu precisava dele funcionando imediatamente. Comecei a pesquisar na internet por uma placa de vídeo nova, mas como eu vivo em uma cidade relativamente pequena, placas de vídeo não só custam uma fortuna por aqui como também são bem difíceis de encontrar. Mas eu não tinha opção: eu precisava do computador funcionando, então eu já estava convencido a comprar uma placa de vídeo nova logo pela manhã no dia seguinte.
Um pouco depois eu resolvi procurar no google por "blown up capacitor" (capacitor explodido, ou algo assim) só pra ver que tipo de resultado ele retornaria, e eu percebi que isso que aconteceu comigo é bastante comum. Estes capacitores são de péssima qualidade e tendem a explodir mesmo, especialmente no caso da minha placa de vídeo (uma XFX Geforce 8600GT): os que explodiram ficam bem na frente da saída de ar do cooler da placa, então basicamente o cooler fica soprando ar quente neles o tempo todo (que belo design, veja você).
Encontrei algumas pessoas dizendo que era relativamente fácil (e barato) trocá-los, então eu decidi tentar. O que poderia dar errado? A placa já estava morta, de qualquer forma. Acordei hoje cedo, fui até uma loja de componentes eletrônicos e comprei três capacitores equivalentes aos que queimaram. Tentei trocá-los eu mesmo, mas meu ferro de solda não era bom o suficiente e eu podia acabar queimando a placa de vez, então eu acabei indo num técnico em eletrônica (desses que consertam TV) e pedi pra ele trocar os capacitores pra mim. Alguns minutos depois ele voltou com a minha placa, já com os novos capacitores:

Agora sim!
Adivinha o que aconteceu? Eu coloquei a placa de volta no computador e tudo voltou a funcionar! Quase não acreditei: eu realmente decidi tentar trocar os capacitores, mas eu não estava esperando que desse muito certo, e já estava me preparando pra gastar mais de 400 reais numa placa de vídeo nova. Fiz alguns testes no computador e aparentemente estava tudo ok. Trabalhei hoje o dia todo no computador e ele está perfeito, como se nada tivesse acontecido.
Custo total do conserto: cerca de 6 reais pelos capacitores e mais 5 reais pro técnico que os soldou pra mim. E, claro, a satisfação de saber que o que parecia ser uma idéia idiota acabou dando certo.
Agora tente imaginar quantas placas de vídeo que poderiam ser consertadas com 10 reais e alguns minutos de trabalho acabam no lixo...
