wechat-api 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|