Skip to content

Instantly share code, notes, and snippets.

@littlekbt
Created September 15, 2016 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save littlekbt/7e011495965682eba3309c85fa861a5b to your computer and use it in GitHub Desktop.
Save littlekbt/7e011495965682eba3309c85fa861a5b to your computer and use it in GitHub Desktop.
# OAuth client side
# move on CUI
# oauth 1.0 Client
#
# 1: get request token
# return request token and request token secret
#
# 2: input verifier
#
# 3: get access token with request token and verifier
# return access token and access token secret
require 'faraday'
require 'faraday_middleware'
require 'uri'
require 'openssl'
require 'cgi'
require 'base64'
require 'pry'
class OauthCli
module Util
def request(host, path, method, params, keys, body=nil)
conn = Faraday.new(:url => host) do |builder|
builder.request :url_encoded
# builder.response :logger
builder.adapter :net_http
end
conn.response :xml, :content_type => /\bxml$/
res = conn.send(method) do |req|
req.headers['Accept'] = 'application/xml'
req.headers['Content-Type'] = 'application/xml'
req.url path
req.params = params.merge({oauth_signature: create_signature(host, path, method, params, keys)})
if body
req.body = body
end
end
res
end
def body_parse(res_body)
res_body
.split('&')
.map{|e| e.split('=')}
.map{|e| [e[0].to_sym, e[1]]}
.to_h
end
private
def create_signature(host, path, method, params, keys)
# key
key = keys.class == Array ? "#{CGI.escape(keys[0])}&#{keys[1]}" : CGI.escape(keys) + '&'
# data
http_method = method.upcase
url = host + path
params = params
.select{|k, v| !v.empty?}
.map{|k, v| [CGI.escape(k.to_s), CGI.escape(v)]}
.to_h
.sort{|(ka, _), (kb, _)| ka <=> kb}
.inject(''){|str, (k, v)| str += "#{k.to_s}=#{v}&"}
.chop
data = [http_method, url, params].map{|e| CGI.escape(e)}.join('&')
create_hmac_sha1(key, data)
end
def create_hmac_sha1(key, text)
digest = OpenSSL::Digest.new('sha1')
Base64.encode64(OpenSSL::HMAC.digest(digest, key, text)).chop
end
def refresh_nonce(env)
env[:oauth_nonce] = ((0..9).to_a + ("a".."z").to_a).sample(20).join
end
def refresh_timestamp(env)
env[:oauth_timestamp] = Time.now.gmtime.to_i.to_s
end
end
end
class OauthCli
include OauthCli::Util
def initialize(consumer_key: nil, consumer_secret: nil, oauth_token: nil, oauth_token_secret: nil, host: nil, path: nil, options: {})
@env = {
host: host,
path: path,
oauth_callback: 'oob',
oauth_consumer_key: consumer_key,
oauth_consumer_secret: consumer_secret,
oauth_token: oauth_token,
oauth_token_secret: oauth_token_secret,
oauth_verifier: '',
oauth_nonce: ((0..9).to_a + ("a".."z").to_a).sample(20).join,
oauth_signature: '',
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Time.now.gmtime.to_i.to_s,
oauth_version: "1.0",
}.merge(options)
end
def get_request_token(path: nil)
p = %i(oauth_consumer_key oauth_nonce oauth_signature_method oauth_timestamp oauth_version oauth_callback scope)
res = request(@env[:host],
path,
'post',
@env.select{|k, _| p.include?(k)},
@env[:oauth_consumer_secret]
)
res_body = body_parse(res.body)
@env.merge!(res_body)
res_body
end
def get_access_token(path: nil, verifier: nil)
p = %i(oauth_consumer_key oauth_nonce oauth_signature_method oauth_timestamp oauth_version oauth_verifier oauth_token)
@env.merge!({oauth_verifier: verifier})
res = request(@env[:host],
path,
'post',
@env.select{|k, _| p.include?(k)}.merge({oauth_token: CGI.unescape(@env[:oauth_token])}),
[@env[:oauth_consumer_secret], @env[:oauth_token_secret]]
)
body_parse(res.body)
end
def upload_image(path, body)
p = %i(oauth_consumer_key oauth_nonce oauth_signature_method oauth_timestamp oauth_version oauth_signature oauth_token)
refresh_nonce(@env)
refresh_timestamp(@env)
res = request(@env[:host],
path,
'post',
@env.select{|k, _| p.include?(k)}.merge({oauth_token: CGI.unescape(@env[:oauth_token])}),
[@env[:oauth_consumer_secret], @env[:oauth_token_secret]],
body=body
)
end
end
# sample
# for hatena api(http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth/consumer)
require './oauth_cli'
oauth_cli = OauthCli.new(
consumer_key: 'consumer_key',
consumer_secret: 'consumer_secret',
host: 'https://www.hatena.com',
options: {scope: 'read_public,write_public,read_private,write_private'}
)
# get request_token
request_token = oauth_cli.get_request_token(path: '/oauth/initiate')
puts "response: #{request_token}"
# access to oauth page(https://www.hatena.ne.jp/oauth/authorize?oauth_token={request_token}) and get verifier
# input verifier
verifier = gets.chop
access_token = oauth_cli.get_access_token(path: '/oauth/token', verifier: verifier)
puts "response: #{access_token}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment