Class: Wechatpay::Api::V3::Client
- Inherits:
-
Object
- Object
- Wechatpay::Api::V3::Client
- Defined in:
- lib/wechatpay/api/v3/client.rb
Constant Summary collapse
- SCHEMA =
'WECHATPAY2-SHA256-RSA2048'.freeze
Instance Attribute Summary collapse
-
#appid ⇒ Object
readonly
Returns the value of attribute appid.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#mch_id ⇒ Object
readonly
Returns the value of attribute mch_id.
-
#rsa_key ⇒ Object
readonly
Returns the value of attribute rsa_key.
-
#serial_no ⇒ Object
readonly
Returns the value of attribute serial_no.
-
#site ⇒ Object
Returns the value of attribute site.
Instance Method Summary collapse
- #authorization_header(http_method, path, body) ⇒ Object
- #authorization_params(http_method, path, body) ⇒ Object
- #cert ⇒ Object
- #connection ⇒ Object
- #dechipher(data, nonce, auth_data) ⇒ Object
- #decrypt(cipher_text, nonce, auth_data) ⇒ Object
- #get(path, params = nil) ⇒ Object
- #handle(resp) ⇒ Object
-
#initialize(appid, mch_id, **opts) ⇒ Client
constructor
A new instance of Client.
- #post(path, data, **headers) ⇒ Object
- #sign_content(content) ⇒ Object
- #sign_with(body, method, path, timestamp, rnd) ⇒ Object
- #update_certs ⇒ Object
- #verify(headers, body) ⇒ Object
Methods included from JSAPI
Methods included from Trade
Constructor Details
#initialize(appid, mch_id, **opts) ⇒ Client
Returns a new instance of Client.
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/wechatpay/api/v3/client.rb', line 18 def initialize(appid, mch_id, **opts) @appid = appid @mch_id = mch_id @rsa_key = OpenSSL::PKey::RSA.new opts[:cert] if opts[:cert] @serial_no = opts[:cert_no] @key = opts[:key] @site = opts[:site] || 'https://api.mch.weixin.qq.com' @logger = Logger.new(STDOUT) end |
Instance Attribute Details
#appid ⇒ Object (readonly)
Returns the value of attribute appid.
13 14 15 |
# File 'lib/wechatpay/api/v3/client.rb', line 13 def appid @appid end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
13 14 15 |
# File 'lib/wechatpay/api/v3/client.rb', line 13 def key @key end |
#logger ⇒ Object
Returns the value of attribute logger.
14 15 16 |
# File 'lib/wechatpay/api/v3/client.rb', line 14 def logger @logger end |
#mch_id ⇒ Object (readonly)
Returns the value of attribute mch_id.
13 14 15 |
# File 'lib/wechatpay/api/v3/client.rb', line 13 def mch_id @mch_id end |
#rsa_key ⇒ Object (readonly)
Returns the value of attribute rsa_key.
13 14 15 |
# File 'lib/wechatpay/api/v3/client.rb', line 13 def rsa_key @rsa_key end |
#serial_no ⇒ Object (readonly)
Returns the value of attribute serial_no.
13 14 15 |
# File 'lib/wechatpay/api/v3/client.rb', line 13 def serial_no @serial_no end |
#site ⇒ Object
Returns the value of attribute site.
14 15 16 |
# File 'lib/wechatpay/api/v3/client.rb', line 14 def site @site end |
Instance Method Details
#authorization_header(http_method, path, body) ⇒ Object
97 98 99 |
# File 'lib/wechatpay/api/v3/client.rb', line 97 def (http_method, path, body) [SCHEMA, (http_method, path, body)].join ' ' end |
#authorization_params(http_method, path, body) ⇒ Object
101 102 103 104 105 106 107 108 109 |
# File 'lib/wechatpay/api/v3/client.rb', line 101 def (http_method, path, body) = Time.now.to_i rnd = SecureRandom.hex signature = sign_with(body, http_method, path, , rnd) [ "mchid=\"#{mch_id}\"", "serial_no=\"#{serial_no}\"", "nonce_str=\"#{rnd}\"", "timestamp=\"#{}\"", "signature=\"#{signature}\"" ].join(',') end |
#cert ⇒ Object
65 66 67 |
# File 'lib/wechatpay/api/v3/client.rb', line 65 def cert Wechatpay::Api::V3::Cert.instance.load || update_certs end |
#connection ⇒ Object
29 30 31 32 33 34 35 36 |
# File 'lib/wechatpay/api/v3/client.rb', line 29 def connection Faraday.new(url: @site) do |conn| conn.request :retry conn.response :logger # conn.response :raise_error conn.adapter :net_http end end |
#dechipher(data, nonce, auth_data) ⇒ Object
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/wechatpay/api/v3/client.rb', line 119 def dechipher(data, nonce, auth_data) chipher = OpenSSL::Cipher.new 'aes-256-gcm' chipher.decrypt chipher.key = key chipher.iv = nonce chipher.padding = 0 chipher.auth_data = auth_data chipher.auth_tag = data[-16, 16] chipher end |
#decrypt(cipher_text, nonce, auth_data) ⇒ Object
111 112 113 114 115 116 117 |
# File 'lib/wechatpay/api/v3/client.rb', line 111 def decrypt(cipher_text, nonce, auth_data) raise :cipher_text_invalid if (cipher_text.try(:length) || 0) < 16 data = Base64.strict_decode64(cipher_text) dec = dechipher(data, nonce, auth_data) dec.update(data[0, data.length - 16]).tap { |s| logger.debug "DEC: #{s}" } + dec.final end |
#get(path, params = nil) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/wechatpay/api/v3/client.rb', line 38 def get(path, params = nil) resp = connection.get(path, params) do |req| path = req.path path = [req.path, Faraday::Utils.build_query(req.params)].join('?') unless params.nil? || params.empty? req.headers['Authorization'] = ('GET', path, nil) req.headers['Accept'] = 'application/json' end handle resp end |
#handle(resp) ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/wechatpay/api/v3/client.rb', line 77 def handle(resp) logger.debug { "HANDLE RESPONSE: #{resp.inspect}" } data = resp.body raise :empty_body unless data && !data.empty? MultiJson.load data, symbolize_keys: true end |
#post(path, data, **headers) ⇒ Object
48 49 50 51 52 53 54 55 |
# File 'lib/wechatpay/api/v3/client.rb', line 48 def post(path, data, **headers) body = data.is_a?(Hash) ? MultiJson.dump(data) : data resp = connection.post(path, body, headers) do |req| req.headers['Authorization'] = ('POST', path, body) req.headers['Accept'] = 'application/json' end handle resp end |
#sign_content(content) ⇒ Object
91 92 93 94 95 |
# File 'lib/wechatpay/api/v3/client.rb', line 91 def sign_content(content) digest = OpenSSL::Digest::SHA256.new signed = rsa_key.sign(digest, content) Base64.strict_encode64 signed end |
#sign_with(body, method, path, timestamp, rnd) ⇒ Object
85 86 87 88 89 |
# File 'lib/wechatpay/api/v3/client.rb', line 85 def sign_with(body, method, path, , rnd) str = [method, path, , rnd, body].join("\n") + "\n" logger.debug { "Sign Content: #{str.inspect}" } sign_content(str) end |
#update_certs ⇒ Object
69 70 71 72 73 74 75 |
# File 'lib/wechatpay/api/v3/client.rb', line 69 def update_certs certs = get('/v3/certificates')[:data] certs.map do |raw| Wechatpay::Api::V3::Cert.instance.update(raw, &method(:decrypt)) end Wechatpay::Api::V3::Cert.instance end |
#verify(headers, body) ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/wechatpay/api/v3/client.rb', line 57 def verify(headers, body) sha256 = OpenSSL::Digest::SHA256.new key = cert.certificate.public_key sign = Base64.strict_decode64(headers['Wechatpay-Signature']) data = %w[Wechatpay-Timestamp Wechatpay-Nonce].map { |k| headers[k] } key.verify sha256, sign, data.append(body).join("\n") + "\n" end |