lib/enigma.rb in enigma-0.0.1 vs lib/enigma.rb in enigma-0.0.3

- old
+ new

@@ -1,123 +1,90 @@ -$:.unshift(File.dirname(__FILE__)) unless - $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) - require 'rubygems' -require 'cgi' -require 'yaml' -require 'rest_client' -require 'addressable/uri' -require "digest/sha1" -require 'ezcrypto' +require 'bundler/setup' +require 'rack' +require 'rack/test' module Enigma - VERSION = '0.0.1' + SIGNATURE_HEADER = "X_ENIGMA_SIGNATURE" - KEY_LENGTH = 32 - SECRET_LENGTH = 32 + extend self + def self.server_key=(server_key) + @server_key = server_key + end - class Query < Hash + def self.server_key + @server_key + end - def initialize(key, secret, params) - self[:key] = key - self[:params] = Enigma.encode_params(secret, params) - end + def signature(method, path, payload) + message = [method, path, payload].map(&:to_s).inject(&:+) - def to_params - params = '' - stack = [] - - each do |k, v| - if v.is_a?(Hash) - stack << [k,v] - else - params << "#{k}=#{v}&" - end - end - - stack.each do |parent, hash| - hash.each do |k, v| - if v.is_a?(Hash) - stack << ["#{parent}[#{k}]", v] - else - params << "#{parent}[#{k}]=#{v}&" - end - end - end - - params.chop! # trailing & - params - end + digest = OpenSSL::Digest::Digest.new("sha512") + OpenSSL::HMAC.hexdigest(digest, self.server_key, message).to_s end - class KeyGenerator - def self.generate(length = 10) - Digest::SHA1.hexdigest(Time.now.to_s + rand(12341234).to_s)[1..length] + def matches?(actual_signature, method, path, payload) + matched = true + expected_signature = self.signature(method, path, payload) + expected_signature.each_char.zip(actual_signature.to_s.each_char).each do |expected, actual| + matched = false if expected != actual end - end - def self.generate_key - KeyGenerator.generate(KEY_LENGTH) + matched end - def self.generate_secret - KeyGenerator.generate(SECRET_LENGTH) - end + class Client + def initialize(options) + @host = options[:host] || 'localhost' + @port = options[:port] || 80 + @ssl = options[:ssl] || false + @certificate = options[:certificate] + end - def self.find_secret(&block) - @find_secret = block - end + attr_reader :host, :port, :ssl, :certificate, :version - def self.authenticate(params={}) - if @find_secret.nil? - raise "Pass a block to #{self.name}.find_secret which returns - secret for the given key. See documentation for details." - end + HTTP_METHODS = [:get, :post, :put, :delete] + HTTP_METHODS.each do |method| + define_method(method) do |path, *args| + payload = args.first + execute method, path, payload + end + end - self.decode_params(@find_secret.call(params[:key]), params[:params]) - end + def http + base = "#{ssl ? "https" : "http"}://#{host}:#{port}" + Class.new do + include HTTParty + base_uri base + end + end - def self.encrypt(secret, data) - key = EzCrypto::Key.with_password(secret, "salt") - key.encrypt(data) - end + def execute(method, path, payload) + response = http.send(method, path, + :headers => headers(method, path, payload), + :body => payload, + :timeout => TIMEOUT + ) - def self.decrypt(secret, data) - key = EzCrypto::Key.with_password(secret, "salt") - key.decrypt(data) - end + response.body + end - def self.encode_params(secret, params) - CGI::escape( - encrypt( - secret, [ YAML::dump(params.sort {|a,b| a[0].to_s <=> b[0].to_s}) ]. - pack('m') - ) - ) - end + TIMEOUT = 60 * 5 - def self.decode_params(secret, signed_params) - begin - params = {} - YAML::load(decrypt(secret, CGI::unescape(signed_params)).unpack('m').first).each do |key, value| - params[key] = value - end - return params - rescue - return nil - end - end + private - class Client - def initialize(key, secret) - @key = key - @secret = secret - end + def headers(method, url, payload) + {Enigma::SIGNATURE_HEADER => + Enigma.signature(method, url, payload) + } + end - def get(url, params={}) - query = Query.new(@key, @secret, params) - RestClient.get("#{url}?#{query.to_params}") - end - end + def scheme + @ssl ? 'https' : 'http' + end + def base_url + "#{scheme}://#{host}:#{port}" + end + end end