require 'optparse'
require 'oauth'
module OAuth
class CLI
SUPPORTED_COMMANDS = %w(sign)
attr_reader :command
attr_reader :options
attr_reader :stdout
def self.execute(stdout, arguments = [])
self.new.execute(stdout, arguments)
end
def initialize
@options = {}
end
def execute(stdout, arguments = [])
@stdout = stdout
extract_command_and_parse_options(arguments)
if sufficient_options? && valid_command?
case command
when "sign"
parameters = prepare_parameters
request = OAuth::RequestProxy.proxy \
"method" => options[:method],
"uri" => options[:uri],
"parameters" => parameters
if verbose?
stdout.puts "OAuth parameters:"
request.oauth_parameters.each do |k,v|
stdout.puts " " + [k, v] * ": "
end
stdout.puts
if request.non_oauth_parameters.any?
stdout.puts "Parameters:"
request.non_oauth_parameters.each do |k,v|
stdout.puts " " + [k, v] * ": "
end
stdout.puts
end
end
request.sign! \
:consumer_secret => options[:oauth_consumer_secret],
:token_secret => options[:oauth_token_secret]
if verbose?
stdout.puts "Method: #{request.method}"
stdout.puts "URI: #{request.uri}"
stdout.puts "Normalized params: #{request.normalized_parameters}" unless options[:xmpp]
stdout.puts "Signature base string: #{request.signature_base_string}"
if options[:xmpp]
stdout.puts
stdout.puts "XMPP Stanza:"
stdout.puts <<-EOS
#{request.oauth_consumer_key}
#{request.oauth_token}
#{request.oauth_signature_method}
#{request.oauth_signature}
#{request.oauth_timestamp}
#{request.oauth_nonce}
#{request.oauth_version}
EOS
stdout.puts
stdout.puts "Note: You may want to use bare JIDs in your URI."
stdout.puts
else
stdout.puts "OAuth Request URI: #{request.signed_uri}"
stdout.puts "Request URI: #{request.signed_uri(false)}"
stdout.puts "Authorization header: #{request.oauth_header(:realm => options[:realm])}"
end
stdout.puts "Signature: #{request.oauth_signature}"
stdout.puts "Escaped signature: #{OAuth::Helper.escape(request.oauth_signature)}"
else
stdout.puts signature
end
end
else
usage
end
end
protected
def extract_command_and_parse_options(arguments)
@command = arguments[-1]
parse_options(arguments[0..-1])
end
def option_parser
option_parser = OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options] "
# defaults
options[:oauth_nonce] = OAuth::Helper.generate_key
options[:oauth_signature_method] = "HMAC-SHA1"
options[:oauth_timestamp] = OAuth::Helper.generate_timestamp
options[:oauth_version] = "1.0"
options[:params] = ""
opts.on("--consumer-key KEY", "Specifies the consumer key to use.") do |v|
options[:oauth_consumer_key] = v
end
opts.on("--consumer-secret SECRET", "Specifies the consumer secret to use.") do |v|
options[:oauth_consumer_secret] = v
end
opts.on("--method METHOD", "Specifies the method (e.g. GET) to use when signing.") do |v|
options[:method] = v
end
opts.on("--nonce NONCE", "Specifies the none to use.") do |v|
options[:oauth_nonce] = v
end
opts.on("--parameters PARAMS", "Specifies the parameters to use when signing.") do |v|
options[:params] = v
end
opts.on("--signature-method METHOD", "Specifies the signature method to use; defaults to HMAC-SHA1.") do |v|
options[:oauth_signature_method] = v
end
opts.on("--secret SECRET", "Specifies the token secret to use.") do |v|
options[:oauth_token_secret] = v
end
opts.on("--timestamp TIMESTAMP", "Specifies the timestamp to use.") do |v|
options[:oauth_timestamp] = v
end
opts.on("--token TOKEN", "Specifies the token to use.") do |v|
options[:oauth_token] = v
end
opts.on("--realm REALM", "Specifies the realm to use.") do |v|
options[:realm] = v
end
opts.on("--uri URI", "Specifies the URI to use when signing.") do |v|
options[:uri] = v
end
opts.on("--version VERSION", "Specifies the OAuth version to use.") do |v|
options[:oauth_version] = v
end
opts.on("--no-version", "Omit oauth_version.") do
options[:oauth_version] = nil
end
opts.on("--xmpp", "Generate XMPP stanzas.") do
options[:xmpp] = true
options[:method] ||= "iq"
end
opts.on("-v", "--verbose", "Be verbose.") do
options[:verbose] = true
end
end
end
def parse_options(arguments)
option_parser.parse!(arguments)
end
def prepare_parameters
escaped_pairs = options[:params].split(/[&,]/).collect do |pair|
Hash[*pair.split("=")].collect do |k,v|
[CGI.escape(k.strip), CGI.escape(v.strip)] * "="
end
end
querystring = escaped_pairs * "&"
cli_params = CGI.parse(querystring)
{
"oauth_consumer_key" => options[:oauth_consumer_key],
"oauth_nonce" => options[:oauth_nonce],
"oauth_timestamp" => options[:oauth_timestamp],
"oauth_token" => options[:oauth_token],
"oauth_signature_method" => options[:oauth_signature_method],
"oauth_version" => options[:oauth_version]
}.reject { |k,v| v.nil? || v == "" }.merge(cli_params)
end
def sufficient_options?
options[:oauth_consumer_key] && options[:oauth_consumer_secret] && options[:method] && options[:uri]
end
def usage
stdout.puts option_parser.help
stdout.puts
stdout.puts "Available commands:"
SUPPORTED_COMMANDS.each do |command|
puts " #{command.ljust(15)}"
end
end
def valid_command?
SUPPORTED_COMMANDS.include?(command)
end
def verbose?
options[:verbose]
end
end
end