Chciałbym Wam pokazać jak wykorzystać Rubiego do zalogowania się na stronie www.

Aby tego dokonać musimy przesłać żądanie oraz odebrać odpowiedź, wyodrębnić ciastko i korzystać z niego do surfowania po portalu (będąc już zalogowanym).

Za przykład portalu gdzie można się zalogować, posłuży nam MyBrute. Jest to miejsce gdzie hoduje się własnego "barbarzyńcę".

Zanim przystąpimy do właściwej części, dołączmy biblioteki których potrzebujemy oraz stwórzmy sobie własną klasę błędów:

require 'net/http'
require 'uri'

module Exceptions
  class InvalidNameOrPassword < StandardError; end
end

Utworzymy sobie model o nazwie MyBrute który będzie odzwierciedlał naszego Brute'a:

class MyBrute
  # Tutaj pójdą metody publiczne
  private
  # A tutaj prywatne
end

Pierwsze co powinniśmy móc zrobić, to stworzyć naszego wojownika. W tym celu dodamy metodę inicjalizującą, która utworzy nam obiekt Net::HTTP, zapamięta co trzeba i zaloguje w systemie.

  def initialize(name, pass)
    @name = name
    @password = pass
    @request = Net::HTTP.new("#{name}.mybrute.com", 80)
    login!
  end

Wszystko byłoby fajnie, tylko gdzie jest metoda login!? Tutaj:

  def login!
    resp, data = @request.post('/login', "pass=#{@password}")
    @cookie = get_cookie(resp)
  end

Logowanie jest bardzo proste, wysyłamy POSTem hasło a następnie odbieramy wyniki. W wynikach mamy ciastko z pomocą którego się będziemy identyfikować. Musimy je jednak wyciągnąć z naszej odpowiedzi. W tym celu skorzystamy z metody get_cookie, która wygląda tak:

  def get_cookie(resp)
    begin
      resp.response['set-cookie'].split('; ')[0]
    rescue
      raise Exceptions::InvalidNameOrPassword
    end
  end

W przypadku ciastka (co dla portalu MyBrute jest równoznaczne z błędnym logowaniem) zwracamy wyjątek, z racji tego że nie jest to standardowe zachowanie w naszm modelu.

Od teraz jesteśmy zalogowani na naszego Brute'a i możemy np dołączyć do turnieju:

  def join_tournament!
    @request.get2("/sub",{'Cookie' => @cookie})
  end

Zasadniczo, całość operacji sprowadza się do przesyłania odpowiednich danych, za pomocą odpowiedniego typu żadania, autoryzując się przy okazji ciastkiem. Jeśli chodzi o toczenie walk, to tam jest jeszcze klucz identyfikacyjny potrzebny który jest generowany po stronie serwera. Nie chciało mi się tego rozgryzać ;) więc pozostawię to dla dociekliwych. Poniżej prezentuję jeszcze całość kodu oraz wykorzystanie:

require 'net/http'
require 'uri'

module Exceptions
  class InvalidNameOrPassword < StandardError; end
end


class MyBrute
  def initialize(name, pass)
    @name = name
    @password = pass
    @request = Net::HTTP.new("#{name}.mybrute.com", 80)
    login!
  end

  def join_tournament!
    @request.get2("/sub",{'Cookie' => @cookie})
  end

  private

  def login!
    resp, data = @request.post('/login', "pass=#{@password}")
    @cookie = get_cookie(resp)
  end

  def get_cookie(resp)
    begin
      resp.response['set-cookie'].split('; ')[0]
    rescue
      raise Exceptions::InvalidNameOrPassword
    end
  end
end

Wykorzystanie:

brute = MyBrute.new('login', 'haslo')
brute.join_tournament!