# This module contains the client code for Vanilla jsConnect single sign on
# Author:: Todd Burry (mailto:todd@vanillaforums.com)
# Version:: 1.0b
# Copyright:: Copyright 2008, 2009 Vanilla Forums Inc.
# License http://www.opensource.org/licenses/gpl-2.0.php GPLv2


module JsConnect

  @@log = Logging.logger[JsConnect]

  def JsConnect.error(code, message)
    return {"error" => code, "message" => message}
  end

  def JsConnect.getJsConnectString(user, request = {}, client_id = "", secret = "", secure = true)
    error = nil

    timestamp = request["timestamp"].to_i
    current_timestamp = JsConnect.timestamp

    if secure
      # Make sure the request coming in is signed properly

      if !request['client_id']
        error = JsConnect.error('invalid_request', 'The client_id parameter is missing.')
      elsif request['client_id'] != client_id
        error = JsConnect.error('invalid_client', "Unknown client #{request['client_id']}.")
      elsif request['timestamp'].nil? and request['signature'].nil?
        @@log.debug("no timestamp right? #{request['timestamp']}, #{request['signature']}")
        if user and !user.empty?
          error = {'name' => user['name'], 'photourl' => user['photourl']}
        else
          error = {'name' => '', 'photourl' => ''}
        end
      elsif request['timestamp'].nil?
        error = JsConnect.error('invalid_request', 'The timestamp is missing or invalid.')
      elsif !request['signature']
        error = JsConnect.error('invalid_request', 'The signature is missing.')
      elsif (current_timestamp - timestamp).abs > 30 * 60
        error = JsConnect.error('invalid_request', 'The timestamp is invalid.')
      else
        # Make sure the timestamp's signature checks out.
        timestamp_sig = Digest::MD5.hexdigest(timestamp.to_s + secret)
        if timestamp_sig != request['signature']
          error = JsConnect.error('access_denied', 'Signature invalid.')
        end
      end
    end

    if error
      @@log.debug("not valid request: #{error}")
      result = error
    elsif user and !user.empty?
      result = user.clone
      @@log.debug("logging in: #{error}")
      JsConnect.signJsConnect(result, client_id, secret, true)
    else
      @@log.debug("anonymous")
      result = {"name" => "", "photourl" => ""}
    end

    json = ActiveSupport::JSON.encode(result);
    if request["callback"]
      return "#{request["callback"]}(#{json});"
    else
      return json
    end
  end

  def JsConnect.signJsConnect(data, client_id, secret, set_data = false)
    # Build the signature string. This is essentially a querystring representation of data, sorted by key
    keys = data.keys.sort { |a,b| a.downcase <=> b.downcase }

    sig_str = ""

    keys.each do |key|
      if sig_str.length > 0
        sig_str += "&"
      end

      value = data[key]
      @@log.debug("key #{key}, value #{value}")
      sig_str += CGI.escape(key) + "=" + CGI.escape(value)
    end

    signature = Digest::MD5.hexdigest(sig_str + secret);

    if set_data
      data["clientid"] = client_id
      data["signature"] = signature
    end
    return signature
  end

  def JsConnect.timestamp
    return Time.now.to_i
  end
end