<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -3,4 +3,5 @@
 coverage
 rdoc
 pkg
-*.lwp
\ No newline at end of file
+*.lwp
+config.yml
\ No newline at end of file</diff>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -2,156 +2,129 @@ require &quot;rubygems&quot;
 require &quot;uri&quot;
 require &quot;digest/sha1&quot;
 require &quot;base64&quot;
-require &quot;curl&quot;
 
-class Cloudquery
-  
-  KEEP_ALIVE = true
-  RAISE_EXCEPTIONS = false
-  INSECURE_ENDPOINT = &quot;http://api.xoopit.com/v0/&quot;
-  SECURE_ENDPOINT = &quot;https://api.xoopit.com/v0/&quot;
-  SIGNING_METHOD = &quot;SHA1&quot;
-  
-  COOKIE_JAR = '.cookies.lwp'
+module Cloudquery
+  SCHEME = &quot;https&quot;.freeze
+  HOST = &quot;api.xoopit.com&quot;.freeze
+  PATH = &quot;/v0&quot;.freeze
   
   API_PATHS = {
-    :authenticate =&gt; 'auth',
+    :account =&gt; &quot;account&quot;,
   }.freeze
-  
-  attr_writer :secret
-  attr_reader :account_name, :stats
-  attr_reader :endpoint_url, :scheme, :host, :port, :path
-  attr_reader :signing_method
-  
-  def initialize(account_name, options={})
-    @account_name = account_name
-    @secret = options[:secret]
 
-    prepare_endpoint_ivars(options)
-    
-    @signing_method = SIGNING_METHOD
-    @stats = {
-      :info =&gt; nil,
-      :timing =&gt; nil,
-    }
-  end
-  
-  def secure?
-    !!@secure
-  end
+
+  SIGNING_METHOD = &quot;SHA1&quot;
+  COOKIE_JAR = &quot;.cookies.lwp&quot;
   
-  # Signs a request in preparation for transit to the @endpoint_url
-  def sign_request_url(path, params={})
-    params['x_name'] = @account_name
-    params['x_method'] = @signing_method
-    params['x_time'] = Time.now.to_i_with_milliseconds
-    params['x_nonce'] = Crypto::Random.number
+  class Request
+    attr_accessor :method, :headers, :scheme, :host, :port, :path, :params, :body
     
-    query_str = params.to_query_string
-    constructed_url = construct_url(path, query_str)
-    append_signature(constructed_url)
-  end
-  
-  # Authenticate the account using the password
-  def authenticate(password)
-    raise &quot;Authentication using this method is only allowed over HTTPS&quot; unless secure?
+    def initialize(options={})
+      @method = options[:method] || 'POST'
+      @headers = options[:headers] || {}
+      @scheme = options[:scheme] || SCHEME
+      @host = options[:host] || HOST
+      @port = options[:port] || URI::HTTPS::DEFAULT_PORT
+      @path = options[:path] || PATH
+      @params = options[:params] || {}
+      @body = options[:body]
+    end
     
-    params = {
-      'name' =&gt; @account_name,
-      'password' =&gt; password,
-    }
+    def add_authentication_params(account)
+      @params['x_name'] = account
+      @params['x_time'] = Time.now.to_i_with_milliseconds
+      @params['x_nonce'] = Cloudquery::Crypto::Random.number
+      @params['x_method'] = SIGNING_METHOD
+    end
+        
+    def request_uri
+      URI.build(:path =&gt; @path, :query =&gt; query_str).to_s
+    end
     
-    request = ['POST', construct_url(API_PATHS[:authenticate]), params.to_query_string]
-    send_request(request)
-  end
-
-private
-  def prepare_endpoint_ivars(options)
-    @secure = !options[:use_http]
-    @endpoint_url = @secure ? SECURE_ENDPOINT : INSECURE_ENDPOINT
-    e = URI.parse(@endpoint_url)
-    @scheme, @host, @path = e.select(:scheme, :host, :path)
-  end
-
-  def construct_url(api_path, query_str=&quot;&quot;)
-    uri_class = secure? ? URI::HTTPS : URI::HTTP
-    uri = uri_class.build({
-      :scheme =&gt; @scheme,
-      :host =&gt; @host,
-      :path =&gt; @path,
-    })
-    uri.merge!(api_path)
-    uri.query = query_str unless query_str.to_s.empty?
-    uri.to_s
-  end
-
-  def append_signature(url)
-    signer = case signing_method
-    when &quot;SHA1&quot;; Crypto::Sha1
-    else; raise &quot;The #{signing_method} signing method is not supported&quot;
+    def signed_request_uri(secret)
+      sign(request_uri, secret)
     end
-
-    signable_url = normalize_url_for_signing(url)
-    signature = signer.sign(@secret, signable_url)
-    url_safe_signature = URI.escape(signature.tr('+/', '-_'), /=/)
-    &quot;#{url}&amp;x_sig=#{url_safe_signature}&quot;
-  end
-  
-  # Expects a rack-style request descriptor
-  # e.g. [HTTP_VERB, url, body]
-  def send_request(descriptor)
-    verb, url, body = descriptor
     
-    @curl ||= Curl::Easy.new do |c|
-      c.enable_cookies = true
-      c.cookiejar = COOKIE_JAR
-      c.verbose = true
+    def uri
+      base_uri.merge(request_uri).to_s
     end
     
-    @curl.url = url
+    def signed_uri(secret)
+      base_uri.merge(signed_request_uri).to_s
+    end
+    
+  private
+    def append_signature(uri, secret)
+      signature = Crypto::Sha1.sign(secret, uri)
+      url_safe_signature = URI.escape(signature.tr('+/', '-_'), /=/)
+      &quot;#{uri}&amp;x_sig=#{url_safe_signature}&quot;
+    end
     
-    case verb
-    when 'GET'
-      @curl.http_get
-    when 'POST'
-      puts body
-      @curl.http_post(body)
+    def query_str
+       @params.to_params
     end
     
+    def base_uri
+      URI.build(:scheme =&gt; @scheme, :host =&gt; @host, :port =&gt; @port)
+    end
+    
+    def hash_to_params(hash)
+      hash.map { |k, v| URI.escape(&quot;#{k}=#{v}&quot;) }.join('&amp;')
+      URI.escape(query_str, /@/)
+    end
   end
   
-  def normalize_url_for_signing(url)
-    URI.parse(url).request_uri
-  end
-end
+  module Crypto
+    module Random
+      extend self
 
-module Crypto
-  module Random
-    extend self
-    
-    SecureRandom = (defined?(::SecureRandom) &amp;&amp; ::SecureRandom) || (defined?(::ActiveSupport::SecureRandom) &amp;&amp; ::ActiveSupport::SecureRandom)
-    
-    if SecureRandom
-      def number
-        &quot;#{SecureRandom.random_number}.#{Time.now.to_i}&quot;[2..-1]
+      SecureRandom = (defined?(::SecureRandom) &amp;&amp; ::SecureRandom) || (defined?(::ActiveSupport::SecureRandom) &amp;&amp; ::ActiveSupport::SecureRandom)
+      if SecureRandom
+        def number
+          &quot;#{SecureRandom.random_number}.#{Time.now.to_i}&quot;[2..-1]
+        end
+      else
+        def number
+          &quot;#{rand.to_s}.#{Time.now.to_i}&quot;[2..-1]
+        end
       end
-    else
-      def number
-        &quot;#{rand.to_s}.#{Time.now.to_i}&quot;[2..-1]
+
+    end
+
+    module Sha1
+      extend self
+
+      def sign(*tokens)
+        tokens = tokens.flatten
+        digest = Digest::SHA1.digest(tokens.join)
+        Base64.encode64(digest).chomp
       end
+
     end
-    
   end
   
-  module Sha1
-    extend self
+  class Client
+    attr_reader :account
+    attr_writer :secret
+
+    def initialize(options={})
+      @account = options[:account]
+      @secret = options[:secret]
+      @secure = options[:secure] != false # must pass false for insecure
+    end
     
-    def sign(*tokens)
-      tokens = tokens.flatten
-      digest = Digest::SHA1.digest(tokens.join)
-      Base64.encode64(digest).chomp
+    def get_account
+      send_request Request.new(:path =&gt; build_path(API_PATHS[:account], account))
     end
     
+    private
+    def send_request(request)
+      p request
+    end
+    
+    def build_path(*path_elements)
+      path_elements.flatten.unshift(PATH).join('/')
+    end
   end
 end
 
@@ -160,11 +133,3 @@ class Time
     (to_f * 1000).to_i
   end
 end
-
-class Hash
-  
-  def to_query_string
-    query_str = map { |k, v| URI.escape(&quot;#{k}=#{v}&quot;) }.join('&amp;')
-    URI.escape(query_str, /@/)
-  end
-end
\ No newline at end of file</diff>
      <filename>lib/cloudquery.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,130 +1,63 @@
 require 'spec_helper'
 
-describe Cloudquery do
+describe Cloudquery::Request do
   before(:each) do
-    @valid_arguments = ['account', {}]
+    @valid_options = {
+      :scheme =&gt; 'http',
+      :host =&gt; 'example.com',
+      :path =&gt; '/v0/',
+    }
   end
   
-  def client
-    return @client if defined?(@client)
-    @client = Cloudquery.new(*@valid_arguments)
-    @client.stub!(:send_request)
-    @client
+  def request(additional_options={})
+    return @request if defined?(@request)
+    @request = Cloudquery::Request.new(@valid_options.merge(additional_options))
   end
-  
-  it &quot;instantiates when passed valid arguments&quot; do
-    lambda { client }.should_not raise_error
-  end
-  
-  describe &quot;API endpoint&quot; do
-    it &quot;uses the secure endpoint by default&quot; do
-      client.endpoint_url.should == Cloudquery::SECURE_ENDPOINT
-    end
 
-    it &quot;parses the scheme from the endpoint&quot; do
-      client.scheme.should == URI.parse(Cloudquery::SECURE_ENDPOINT).scheme
-    end
+  it &quot;instantiates with valid options&quot; do
+    lambda { request }.should_not raise_error
+  end
 
-    it &quot;parses the host from the endpoint&quot; do
-      client.host.should == URI.parse(Cloudquery::SECURE_ENDPOINT).host
+  describe &quot;add_authentication_params&quot; do
+    before(:each) do
+      request.add_authentication_params('account')
     end
-
-    it &quot;parses the path from the endpoint&quot; do
-      client.path.should == URI.parse(Cloudquery::SECURE_ENDPOINT).path
+    
+    it &quot;should add the x_name parameter with the account name&quot; do
+      request.params.should have_key('x_name')
+      request.params['x_name'].should == 'account'
     end
-  end
-  
-  describe &quot;URL munging&quot; do
-    it &quot;merges paths together to create a full URL&quot; do
-      path = &quot;path/elements/and/stuff&quot;
-      client.send(:construct_url, path).should == &quot;#{client.endpoint_url}#{path}&quot;
+    
+    it &quot;should add the x_time parameter with the current milliseconds since epoch&quot; do
+      request.params.should have_key('x_time')
+      request.params['x_time'].should be_close(Time.now.to_i_with_milliseconds, 100)
     end
     
-    it &quot;merges paths and the query string to create a full URL&quot; do
-      path = &quot;a/path&quot;
-      query_string = &quot;query=param&amp;foo=bar&quot;
-      client.send(:construct_url, path, query_string).should == &quot;#{client.endpoint_url}#{path}?#{query_string}&quot;
+    it &quot;should add the x_nonce parameter of the format \d+.\d+&quot; do
+      request.params.should have_key('x_nonce')
+      request.params['x_nonce'].should match(/^\d+.\d+$/)
     end
     
-    it &quot;extracts the normalized, signable url from the full URL&quot; do
-      request_uri = &quot;/path/elements/?query=string&quot;
-      url = &quot;https://subdomain.domain.tld:9027#{request_uri}&quot;
-      client.send(:normalize_url_for_signing, url).should == request_uri
+    it &quot;should add the x_method parameter with the signing method name&quot; do
+      request.params.should have_key('x_method')
+      request.params['x_method'].should == Cloudquery::SIGNING_METHOD
     end
   end
-  
+
+  describe &quot;append_signature&quot; do
+    it &quot;should append the signature as the x_sig parameter at the end of the query string&quot;
+  end
+end
+
+describe Cloudquery::Crypto::Random do
   describe &quot;nonce generation&quot; do
     it &quot;generates a nonce with a random number, a dot, and the current time&quot; do
-      nonce = Crypto::Random.number
+      nonce = Cloudquery::Crypto::Random.number
       nonce.should match(/^\d+.\d+$/)
       random_digits, time = nonce.split('.')
       time.to_i.should be_close(Time.now.to_i, 1)
       random_digits.should match(/^\d+$/)
     end
   end
-  
-  describe &quot;cryptographic signing&quot; do
-    before(:each) do
-      @url = 'https://a.url.to-sign/with/a/path'
-    end
-    
-    it &quot;supports SHA1 as the signing method&quot; do
-      client.signing_method.should == 'SHA1'
-      lambda {
-        client.send(:append_signature, @url)
-      }.should_not raise_error
-    end
-    
-    it &quot;raises an exception for unsupported signing methods&quot; do
-      client.should_receive(:signing_method).at_least(:once).and_return(&quot;BCrypt&quot;)
-      lambda {
-        client.send(:append_signature, @url)
-      }.should raise_error(&quot;The BCrypt signing method is not supported&quot;)
-    end
-    
-    it &quot;appends the signature as the x_sig parameter at the end of the full url&quot; do
-      signed_url = client.send(:append_signature, @url)
-      signed_url.should match(/^#{@url}/)
-      signed_url.should match(/x_sig=[-\w]+(?:%3D)*$/)
-    end
-    
-    it &quot;encodes the signature with url-safe base64&quot; do
-      signature = client.send(:append_signature, @url).split('x_sig=').last
-      signature.should_not include('+')
-      signature.should_not include('/')
-    end
-  end
-  
-  describe &quot;request url signing&quot; do
-    it &quot;keeps reserved characters out of the query&quot; do
-      params = {&quot;escape_me&quot; =&gt; &quot;account@example.com&quot;, &quot;foo&quot; =&gt; &quot;bar&quot;}
-      url = &quot;https://subdomain.domain.tld:9027/path/elements/&quot;
-      client.sign_request_url(url, params).should_not match(/@/)
-    end
-  end
-  
-  describe &quot;#authenticate&quot; do
-    it &quot;raises an exception unless a password is provided&quot; do
-      lambda { client.authenticate }.should raise_error(ArgumentError)
-      
-    end
-    
-    it &quot;raises an exception unless the client is secure&quot; do
-      client.should_receive(:secure?).and_return(false)
-      lambda {
-        client.authenticate('password')
-      }.should raise_error(&quot;Authentication using this method is only allowed over HTTPS&quot;)
-      
-    end
-    
-    it &quot;sends a request with a descriptor to post params to the authentication url&quot; do
-      params = {'name' =&gt; @valid_arguments.first, 'password' =&gt; 'password'}
-      client.should_receive(:send_request) do |request_descriptor|
-        request_descriptor.shift.should == 'POST'
-        request_descriptor.shift.should == client.send(:construct_url, Cloudquery::API_PATHS[:authenticate])
-        request_descriptor.shift.should == params.to_query_string
-      end
-      client.authenticate('password')
-    end
-  end
 end
+  
\ No newline at end of file</diff>
      <filename>spec/cloudquery_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>283ada2b586b1953ca8cc651a3b05d5528ae25c8</id>
    </parent>
  </parents>
  <author>
    <name>Cameron Walters</name>
    <email>cameron.walters@gmail.com</email>
  </author>
  <url>http://github.com/bmizerany/cloudquery/commit/968ac0b598ed1f70c306b506d1dd8e9235d542e3</url>
  <id>968ac0b598ed1f70c306b506d1dd8e9235d542e3</id>
  <committed-date>2009-04-30T13:36:55-07:00</committed-date>
  <authored-date>2009-04-30T13:36:55-07:00</authored-date>
  <message>Refactored into Request and Client. Secrets are the way.</message>
  <tree>ff7e0867fef024102d6c02cb9982e5d36b5efa3e</tree>
  <committer>
    <name>Cameron Walters</name>
    <email>cameron.walters@gmail.com</email>
  </committer>
</commit>
