wechat-api 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/wechat/api.rb +13 -0
- data/lib/wechat/api/client.rb +15 -6
- data/lib/wechat/api/js_ticket.rb +22 -0
- data/lib/wechat/api/util.rb +20 -0
- data/lib/wechat/api/version.rb +1 -1
- data/spec/wechat/api/js_ticket_spec.rb +18 -0
- data/spec/wechat/api/util_spec.rb +19 -0
- data/wechat-api.gemspec +0 -1
- metadata +7 -3
- data/.github/workflows/rake_spec.yml +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3af5535d32a85e57f6ed8f517cb17cbd0e8941e42610bc467a0cdb4a4936f411
|
4
|
+
data.tar.gz: 5de42166d01da0ea3047cc53f87864e85c4454a753b351f62d2c5d4ee64d0871
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d77173f5c03d1bf1bf345a947238b5fa6966de3f67a8ff596670c904b1c9e726856d160be9c30a6c14f8e1ec4e21297a357fdf6fc080bb48b496f9a86db36758
|
7
|
+
data.tar.gz: 608d72719242789c965ae36b3f875806ddfc7d719fc54f4060c6a9b0d9a77ba424ddae1d4713731aafa88bf1dc0da8b1a491274c2834f63f2e41bc0c826fc3ee
|
data/lib/wechat/api.rb
CHANGED
@@ -4,5 +4,18 @@ require 'wechat/api/client'
|
|
4
4
|
module Wechat
|
5
5
|
#
|
6
6
|
module Api
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
def self.client(appid = 'origin_id')
|
10
|
+
var = "@_client_#{appid}"
|
11
|
+
if instance_variable_defined?(var)
|
12
|
+
instance_variable_get(var)
|
13
|
+
elsif block_given?
|
14
|
+
c = yield(Client)
|
15
|
+
instance_variable_set var, c
|
16
|
+
else
|
17
|
+
raise Error, :not_initialized
|
18
|
+
end
|
19
|
+
end
|
7
20
|
end
|
8
21
|
end
|
data/lib/wechat/api/client.rb
CHANGED
@@ -2,6 +2,7 @@ require 'multi_json'
|
|
2
2
|
require 'wechat/api/message'
|
3
3
|
require 'wechat/api/user'
|
4
4
|
require 'wechat/api/util'
|
5
|
+
require 'wechat/api/js_ticket'
|
5
6
|
require 'faraday'
|
6
7
|
require 'logger'
|
7
8
|
|
@@ -18,12 +19,13 @@ module Wechat
|
|
18
19
|
|
19
20
|
API_BASE = 'https://api.weixin.qq.com/cgi-bin/'
|
20
21
|
|
21
|
-
attr_reader :app_id, :secret
|
22
|
-
attr_accessor :logger
|
22
|
+
attr_reader :app_id, :secret, :ticket
|
23
|
+
attr_accessor :logger, :site
|
23
24
|
|
24
25
|
def initialize(app_id, secret)
|
25
26
|
@app_id, @secret = app_id, secret
|
26
27
|
@logger = Logger.new(STDOUT)
|
28
|
+
@ticket = JsTicket.new self
|
27
29
|
@token_file = File.join('/tmp', "wechat-api-#{app_id}")
|
28
30
|
end
|
29
31
|
|
@@ -37,10 +39,11 @@ module Wechat
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def refresh
|
40
|
-
url = format('%stoken',
|
42
|
+
url = format('%stoken', base_url)
|
41
43
|
resp = connection.get(url, token_params)
|
42
44
|
response = MultiJson.load(resp.body)
|
43
45
|
return handle_error(response) if response['errcode']
|
46
|
+
|
44
47
|
@access_token = response['access_token']
|
45
48
|
File.open(@token_file, 'w') { |f| f.write(resp.body) } if @access_token
|
46
49
|
@access_token
|
@@ -72,9 +75,11 @@ module Wechat
|
|
72
75
|
end
|
73
76
|
|
74
77
|
def with_access_token(uri, params, tried = 2)
|
75
|
-
url = format('%s%s',
|
78
|
+
url = format('%s%s', base_url, uri)
|
76
79
|
begin
|
77
80
|
resp = yield(url, params.merge(access_token: access_token))
|
81
|
+
raise ResponseError, resp unless resp.success?
|
82
|
+
|
78
83
|
response = MultiJson.load(resp.body)
|
79
84
|
handle_error(response)
|
80
85
|
rescue AccessTokenExpiredError => e
|
@@ -86,6 +91,10 @@ module Wechat
|
|
86
91
|
|
87
92
|
private
|
88
93
|
|
94
|
+
def base_url
|
95
|
+
site || API_BASE
|
96
|
+
end
|
97
|
+
|
89
98
|
def debug_request
|
90
99
|
response = yield
|
91
100
|
logger.debug { response }
|
@@ -97,9 +106,9 @@ module Wechat
|
|
97
106
|
when 0, nil
|
98
107
|
response
|
99
108
|
when 40_001, 42_001, 40_014
|
100
|
-
|
109
|
+
raise AccessTokenExpiredError, response
|
101
110
|
else
|
102
|
-
|
111
|
+
raise ResponseError, response
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Wechat
|
2
|
+
module Api
|
3
|
+
|
4
|
+
class JsTicket
|
5
|
+
attr_reader :client, :ticket, :expires_at
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def refresh
|
11
|
+
js = client.js_ticket
|
12
|
+
@ticket = js[:ticket]
|
13
|
+
@expires_at = DateTime.now + Rational(js[:expires_in].to_i, 3600*24)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def expired?
|
18
|
+
expires_at.nil? || DateTime.now > expires_at
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/wechat/api/util.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
1
4
|
module Wechat
|
2
5
|
module Api
|
3
6
|
#
|
@@ -32,6 +35,23 @@ module Wechat
|
|
32
35
|
res = get 'ticket/getticket', type: :jsapi
|
33
36
|
res['ticket']
|
34
37
|
end
|
38
|
+
|
39
|
+
def sign(params)
|
40
|
+
str = params.to_a.sort.map { |p| p.join('=') }.join('&')
|
41
|
+
logger.debug { "to_sign: #{str}" }
|
42
|
+
Digest::SHA1.hexdigest str
|
43
|
+
end
|
44
|
+
|
45
|
+
def js_config(url: nil)
|
46
|
+
r = ticket.tap { |j| j.refresh if j.expired? }.ticket
|
47
|
+
nonce = SecureRandom.hex
|
48
|
+
timestamp = Time.now.to_i
|
49
|
+
signature = sign(noncestr: nonce, timestamp: timestamp, jsapi_ticket: r, url: url)
|
50
|
+
{
|
51
|
+
appId: app_id, timestamp: timestamp, nonceStr: nonce,
|
52
|
+
signature: signature
|
53
|
+
}.tap { |hash| logger.debug { "js_config: #{hash}, url: #{url}" } }
|
54
|
+
end
|
35
55
|
end
|
36
56
|
end
|
37
57
|
end
|
data/lib/wechat/api/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
RSpec.describe Wechat::Api::JsTicket do
|
4
|
+
|
5
|
+
let(:client) { double(:client) }
|
6
|
+
subject do
|
7
|
+
Wechat::Api::JsTicket.new client
|
8
|
+
end
|
9
|
+
|
10
|
+
it :refresh do
|
11
|
+
allow(client).to receive(:js_ticket).and_return(expires_in: 7200, ticket: 'bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA')
|
12
|
+
subject.refresh
|
13
|
+
expect(subject.ticket).not_to be_nil
|
14
|
+
should_not be_expired
|
15
|
+
expect(subject.expires_at).to be_a(Date)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
RSpec.describe Wechat::Api::Util do
|
4
|
+
subject { Wechat::Api::Client.new('APPID', 'APPSECRET') }
|
5
|
+
|
6
|
+
before do
|
7
|
+
subject.logger.level = Logger::DEBUG
|
8
|
+
end
|
9
|
+
|
10
|
+
it :js_config do
|
11
|
+
allow(SecureRandom).to receive(:hex).and_return('Wm3WZYTPz0wzccnW')
|
12
|
+
allow_any_instance_of(Time).to receive(:to_i).and_return(1414587457)
|
13
|
+
allow(subject).to receive(:js_ticket).and_return(expires_in: 7200, ticket: 'sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg')
|
14
|
+
js = subject.js_config(url: 'http://mp.weixin.qq.com?params=value')
|
15
|
+
expect(js).not_to be_nil
|
16
|
+
expect(js).to include(signature: '0f9de62fce790f9a083d5c99e95740ceb90c27ed')
|
17
|
+
expect(js).to have_key :appId
|
18
|
+
end
|
19
|
+
end
|
data/wechat-api.gemspec
CHANGED
@@ -13,7 +13,6 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
16
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
17
|
spec.require_paths = ["lib"]
|
19
18
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wechat-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Wong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -143,7 +143,6 @@ executables: []
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
|
-
- ".github/workflows/rake_spec.yml"
|
147
146
|
- ".gitignore"
|
148
147
|
- ".rspec"
|
149
148
|
- Gemfile
|
@@ -153,6 +152,7 @@ files:
|
|
153
152
|
- lib/wechat-api.rb
|
154
153
|
- lib/wechat/api.rb
|
155
154
|
- lib/wechat/api/client.rb
|
155
|
+
- lib/wechat/api/js_ticket.rb
|
156
156
|
- lib/wechat/api/message.rb
|
157
157
|
- lib/wechat/api/user.rb
|
158
158
|
- lib/wechat/api/util.rb
|
@@ -162,6 +162,8 @@ files:
|
|
162
162
|
- lib/wechat/qy/message.rb
|
163
163
|
- spec/spec_helper.rb
|
164
164
|
- spec/wechat/api/client_spec.rb
|
165
|
+
- spec/wechat/api/js_ticket_spec.rb
|
166
|
+
- spec/wechat/api/util_spec.rb
|
165
167
|
- wechat-api.gemspec
|
166
168
|
homepage: https://github.com/lazing/wechat-api
|
167
169
|
licenses:
|
@@ -189,3 +191,5 @@ summary: Wechat API wrapper
|
|
189
191
|
test_files:
|
190
192
|
- spec/spec_helper.rb
|
191
193
|
- spec/wechat/api/client_spec.rb
|
194
|
+
- spec/wechat/api/js_ticket_spec.rb
|
195
|
+
- spec/wechat/api/util_spec.rb
|
@@ -1,20 +0,0 @@
|
|
1
|
-
name: Ruby
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
|
8
|
-
runs-on: ubuntu-latest
|
9
|
-
|
10
|
-
steps:
|
11
|
-
- uses: actions/checkout@v1
|
12
|
-
- name: Set up Ruby 2.6
|
13
|
-
uses: actions/setup-ruby@v1
|
14
|
-
with:
|
15
|
-
ruby-version: 2.6.x
|
16
|
-
- name: Build and test with Rake
|
17
|
-
run: |
|
18
|
-
gem install bundler
|
19
|
-
bundle install --jobs 4 --retry 3
|
20
|
-
bundle exec rake
|