wechat 0.6.8 → 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eda1d074591c670445ef8e73291eb2131e0a595c
4
- data.tar.gz: 576db68d3550ab9ac86c392e2ca6757184e0b114
3
+ metadata.gz: 0dc6d264f5abaaa4f22369e54e341f95ee9d5f50
4
+ data.tar.gz: 52284eb6380ee4969955c512cf95a3fda69e4784
5
5
  SHA512:
6
- metadata.gz: 70af013d27c8a9a144012c564da1d02927d865fcc64837d1bfb371f525503527d830ac80cb53a512927980e717780a8e88d31f15853a4210eb70780d5a7c716e
7
- data.tar.gz: c38169bac4eca6015b9be377d95b3b4ae44511ed3df80ae379d76d3b23077e44867da3c98a15437fb447b6a99757479a4e501cc393e2e87bfda8b5279eb4e9e8
6
+ metadata.gz: 479c18b6cdc4d889a159a81fa9dc9256e83ae6c9543d8f8cc1e42c92cba3618639219287a0b372b3a7ddb56a0c0bae365dc8761a0f0a737839ed090ae0be6026
7
+ data.tar.gz: 64ad4d1f5204fae608786226f07c00761645f4c381d2359235b480bd8cbf6190f5475c2901527d03c9bbb8bece37e359fb4940d15f104fec26708e3d04c9c21c
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.6.9 (released at 1/6/2016)
4
+
5
+ * Fix token refresh bug on multi worker. #76
6
+ * Rewrite the token relative code to add more storage support in future.
7
+
3
8
  ## v0.6.8 (released at 12/25/2015)
4
9
 
5
10
  * Support Rails 5.0.0.beta1.
@@ -1,7 +1,7 @@
1
1
  require 'wechat/api_base'
2
2
  require 'wechat/client'
3
- require 'wechat/access_token'
4
- require 'wechat/jsapi_ticket'
3
+ require 'wechat/token/public_access_token'
4
+ require 'wechat/ticket/public_jsapi_ticket'
5
5
 
6
6
  module Wechat
7
7
  class Api < ApiBase
@@ -10,8 +10,8 @@ module Wechat
10
10
 
11
11
  def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file)
12
12
  @client = Client.new(API_BASE, timeout, skip_verify_ssl)
13
- @access_token = AccessToken.new(@client, appid, secret, token_file)
14
- @jsapi_ticket = JsapiTicket.new(@client, @access_token, jsapi_ticket_file)
13
+ @access_token = Token::PublicAccessToken.new(@client, appid, secret, token_file)
14
+ @jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
15
15
  end
16
16
 
17
17
  def groups
@@ -22,7 +22,9 @@ module Wechat
22
22
  end
23
23
  end
24
24
 
25
- def request(path, header = {}, &block)
25
+ private
26
+
27
+ def request(path, header = {}, &_block)
26
28
  url = "#{header.delete(:base) || base}#{path}"
27
29
  as = header.delete(:as)
28
30
  header.merge!(accept: :json)
@@ -35,8 +37,8 @@ module Wechat
35
37
  case data['errcode']
36
38
  when 0 # for request didn't expect results
37
39
  data
38
- # 42001: access_token超时
39
- # 40014: 不合法的access_token
40
+ # 42001: access_token timeout
41
+ # 40014: invalid access_token
40
42
  # 40001, invalid credential, access_token is invalid or not latest hint
41
43
  # 48001, api unauthorized hint, for qrcode creation # 71
42
44
  when 42001, 40014, 40001, 48001
@@ -47,8 +49,6 @@ module Wechat
47
49
  end
48
50
  end
49
51
 
50
- private
51
-
52
52
  def parse_response(response, as)
53
53
  content_type = response.headers[:content_type]
54
54
  parse_as = {
@@ -1,19 +1,10 @@
1
1
  require 'wechat/api_base'
2
2
  require 'wechat/client'
3
- require 'wechat/access_token'
4
- require 'wechat/corp_jsapi_ticket'
3
+ require 'wechat/token/corp_access_token'
4
+ require 'wechat/ticket/corp_jsapi_ticket'
5
5
  require 'cgi'
6
6
 
7
7
  module Wechat
8
- class CorpAccessToken < AccessToken
9
- def refresh
10
- data = client.get('gettoken', params: { corpid: appid, corpsecret: secret })
11
- data.merge!(created_at: Time.now.to_i)
12
- File.write(token_file, data.to_json) if valid_token(data)
13
- @token_data = data
14
- end
15
- end
16
-
17
8
  class CorpApi < ApiBase
18
9
  attr_reader :agentid
19
10
 
@@ -21,9 +12,9 @@ module Wechat
21
12
 
22
13
  def initialize(appid, secret, token_file, agentid, timeout, skip_verify_ssl, jsapi_ticket_file)
23
14
  @client = Client.new(API_BASE, timeout, skip_verify_ssl)
24
- @access_token = CorpAccessToken.new(@client, appid, secret, token_file)
15
+ @access_token = Token::CorpAccessToken.new(@client, appid, secret, token_file)
25
16
  @agentid = agentid
26
- @jsapi_ticket = CorpJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
17
+ @jsapi_ticket = Ticket::CorpJsapiTicket.new(@client, @access_token, jsapi_ticket_file)
27
18
  end
28
19
 
29
20
  def agent_list
@@ -99,12 +90,12 @@ module Wechat
99
90
  get 'department/list', params: { id: departmentid }
100
91
  end
101
92
 
102
- def user_simplelist(departmentid, fetch_child = 0, status = 0)
103
- get 'user/simplelist', params: { departmentid: departmentid, fetch_child: fetch_child, status: status }
93
+ def user_simplelist(department_id, fetch_child = 0, status = 0)
94
+ get 'user/simplelist', params: { department_id: department_id, fetch_child: fetch_child, status: status }
104
95
  end
105
96
 
106
- def user_list(departmentid, fetch_child = 0, status = 0)
107
- get 'user/list', params: { departmentid: departmentid, fetch_child: fetch_child, status: status }
97
+ def user_list(department_id, fetch_child = 0, status = 0)
98
+ get 'user/list', params: { department_id: department_id, fetch_child: fetch_child, status: status }
108
99
  end
109
100
 
110
101
  def tag_create(tagname, tagid = nil)
@@ -0,0 +1,13 @@
1
+ require 'wechat/ticket/jsapi_base'
2
+
3
+ module Wechat
4
+ module Ticket
5
+ class CorpJsapiTicket < JsapiBase
6
+ def refresh
7
+ data = client.get('get_jsapi_ticket', params: { access_token: access_token.token })
8
+ write_ticket_to_file(data)
9
+ read_ticket_from_file
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ require 'digest/sha1'
2
+
3
+ module Wechat
4
+ module Ticket
5
+ class JsapiBase
6
+ attr_reader :client, :access_token, :jsapi_ticket_file, :access_ticket, :ticket_life_in_seconds, :got_ticket_at
7
+
8
+ def initialize(client, access_token, jsapi_ticket_file)
9
+ @client = client
10
+ @access_token = access_token
11
+ @jsapi_ticket_file = jsapi_ticket_file
12
+ @random_generator = Random.new
13
+ end
14
+
15
+ def ticket
16
+ # Possible two worker running, one worker refresh ticket, other unaware, so must read every time
17
+ read_ticket_from_file
18
+ refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
19
+ access_ticket
20
+ end
21
+
22
+ # Obtain the wechat jssdk config signature parameter and return below hash
23
+ # params = {
24
+ # noncestr: noncestr,
25
+ # timestamp: timestamp,
26
+ # jsapi_ticket: ticket,
27
+ # url: url,
28
+ # signature: signature
29
+ # }
30
+ def signature(url)
31
+ params = {
32
+ noncestr: SecureRandom.base64(16),
33
+ timestamp: Time.now.to_i,
34
+ jsapi_ticket: ticket,
35
+ url: url
36
+ }
37
+ pairs = params.keys.sort.map do |key|
38
+ "#{key}=#{params[key]}"
39
+ end
40
+ result = Digest::SHA1.hexdigest pairs.join('&')
41
+ params.merge(signature: result)
42
+ end
43
+
44
+ protected
45
+
46
+ def read_ticket_from_file
47
+ td = JSON.parse(File.read(jsapi_ticket_file))
48
+ @got_ticket_at = td.fetch('got_ticket_at').to_i
49
+ @ticket_life_in_seconds = td.fetch('expires_in').to_i
50
+ @access_ticket = td.fetch('ticket')
51
+ rescue JSON::ParserError, Errno::ENOENT, KeyError
52
+ refresh
53
+ end
54
+
55
+ def write_ticket_to_file(ticket_hash)
56
+ ticket_hash.merge!('got_ticket_at'.freeze => Time.now.to_i)
57
+ File.write(jsapi_ticket_file, ticket_hash.to_json)
58
+ end
59
+
60
+ def remain_life_seconds
61
+ ticket_life_in_seconds - (Time.now.to_i - got_ticket_at)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,13 @@
1
+ require 'wechat/ticket/jsapi_base'
2
+
3
+ module Wechat
4
+ module Ticket
5
+ class PublicJsapiTicket < JsapiBase
6
+ def refresh
7
+ data = client.get('ticket/getticket', params: { access_token: access_token.token, type: 'jsapi' })
8
+ write_ticket_to_file(data)
9
+ read_ticket_from_file
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ module Wechat
2
+ module Token
3
+ class AccessTokenBase
4
+ attr_reader :client, :appid, :secret, :token_file, :access_token, :token_life_in_seconds, :got_token_at
5
+
6
+ def initialize(client, appid, secret, token_file)
7
+ @appid = appid
8
+ @secret = secret
9
+ @client = client
10
+ @token_file = token_file
11
+ @random_generator = Random.new
12
+ end
13
+
14
+ def token
15
+ # Possible two worker running, one worker refresh token, other unaware, so must read every time
16
+ read_token_from_file
17
+ refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
18
+ access_token
19
+ end
20
+
21
+ protected
22
+
23
+ def read_token_from_file
24
+ td = JSON.parse(File.read(token_file))
25
+ @got_token_at = td.fetch('got_token_at').to_i
26
+ @token_life_in_seconds = td.fetch('expires_in').to_i
27
+ @access_token = td.fetch('access_token')
28
+ rescue JSON::ParserError, Errno::ENOENT, KeyError
29
+ refresh
30
+ end
31
+
32
+ def write_token_to_file(token_hash)
33
+ token_hash.merge!('got_token_at'.freeze => Time.now.to_i)
34
+ File.write(token_file, token_hash.to_json)
35
+ end
36
+
37
+ def remain_life_seconds
38
+ token_life_in_seconds - (Time.now.to_i - got_token_at)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ require 'wechat/token/access_token_base'
2
+
3
+ module Wechat
4
+ module Token
5
+ class CorpAccessToken < AccessTokenBase
6
+ def refresh
7
+ data = client.get('gettoken', params: { corpid: appid, corpsecret: secret })
8
+ write_token_to_file(data)
9
+ read_token_from_file
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'wechat/token/access_token_base'
2
+
3
+ module Wechat
4
+ module Token
5
+ class PublicAccessToken < AccessTokenBase
6
+ def refresh
7
+ data = client.get('token', params: { grant_type: 'client_credential', appid: appid, secret: secret })
8
+ write_token_to_file(data)
9
+ read_token_from_file
10
+ end
11
+ end
12
+ end
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wechat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.8
4
+ version: 0.6.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skinnyworm
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-25 00:00:00.000000000 Z
12
+ date: 2016-01-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -119,19 +119,21 @@ files:
119
119
  - lib/generators/wechat/templates/app/controllers/wechats_controller.rb
120
120
  - lib/generators/wechat/templates/config/wechat.yml
121
121
  - lib/wechat.rb
122
- - lib/wechat/access_token.rb
123
122
  - lib/wechat/api.rb
124
123
  - lib/wechat/api_base.rb
125
124
  - lib/wechat/api_loader.rb
126
125
  - lib/wechat/cipher.rb
127
126
  - lib/wechat/client.rb
128
127
  - lib/wechat/corp_api.rb
129
- - lib/wechat/corp_jsapi_ticket.rb
130
- - lib/wechat/jsapi_base.rb
131
- - lib/wechat/jsapi_ticket.rb
132
128
  - lib/wechat/message.rb
133
129
  - lib/wechat/responder.rb
134
130
  - lib/wechat/signature.rb
131
+ - lib/wechat/ticket/corp_jsapi_ticket.rb
132
+ - lib/wechat/ticket/jsapi_base.rb
133
+ - lib/wechat/ticket/public_jsapi_ticket.rb
134
+ - lib/wechat/token/access_token_base.rb
135
+ - lib/wechat/token/corp_access_token.rb
136
+ - lib/wechat/token/public_access_token.rb
135
137
  homepage: https://github.com/Eric-Guo/wechat
136
138
  licenses:
137
139
  - MIT
@@ -1,39 +0,0 @@
1
- module Wechat
2
- class AccessToken
3
- attr_reader :client, :appid, :secret, :token_file, :token_data
4
-
5
- def initialize(client, appid, secret, token_file)
6
- @appid = appid
7
- @secret = secret
8
- @client = client
9
- @token_file = token_file
10
- end
11
-
12
- def token
13
- begin
14
- @token_data ||= JSON.parse(File.read(token_file))
15
- created_at = token_data['created_at'].to_i
16
- expires_in = token_data['expires_in'].to_i
17
- fail 'token_data may be expired' if Time.now.to_i - created_at >= expires_in - 3 * 60
18
- rescue
19
- refresh
20
- end
21
- valid_token(@token_data)
22
- end
23
-
24
- def refresh
25
- data = client.get('token', params: { grant_type: 'client_credential', appid: appid, secret: secret })
26
- data.merge!('created_at'.freeze => Time.now.to_i)
27
- File.write(token_file, data.to_json) if valid_token(data)
28
- @token_data = data
29
- end
30
-
31
- private
32
-
33
- def valid_token(token_data)
34
- access_token = token_data['access_token']
35
- fail "Response didn't have access_token" if access_token.blank?
36
- access_token
37
- end
38
- end
39
- end
@@ -1,13 +0,0 @@
1
- require 'wechat/jsapi_base'
2
-
3
- module Wechat
4
- class CorpJsapiTicket < JsapiBase
5
- # refresh jsapi ticket
6
- def refresh
7
- data = client.get('get_jsapi_ticket', params: { access_token: access_token.token })
8
- data.merge!('created_at'.freeze => Time.now.to_i)
9
- File.open(jsapi_ticket_file, 'w') { |f| f.write(data.to_json) } if valid_ticket(data)
10
- @jsapi_ticket_data = data
11
- end
12
- end
13
- end
@@ -1,67 +0,0 @@
1
- # coding: utf-8
2
- require 'digest/sha1'
3
-
4
- module Wechat
5
- class JsapiBase
6
- attr_reader :client, :access_token, :jsapi_ticket_file, :jsapi_ticket_data
7
-
8
- def initialize(client, access_token, jsapi_ticket_file)
9
- @client = client
10
- @access_token = access_token
11
- @jsapi_ticket_file = jsapi_ticket_file
12
- end
13
-
14
- # 获取微信 jssdk 签名所需的 jsapi_ticket, 返回具有如下结构的 hash:
15
- # {
16
- # "errcode":0,
17
- # "errmsg":"ok",
18
- # "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
19
- # "expires_in":7200
20
- # }
21
- def ticket
22
- begin
23
- @jsapi_ticket_data ||= JSON.parse(File.read(jsapi_ticket_file))
24
- created_at = jsapi_ticket_data['created_at'].to_i
25
- expires_in = jsapi_ticket_data['expires_in'].to_i
26
- if Time.now.to_i - created_at >= expires_in - 3 * 60
27
- fail 'jsapi_ticket may be expired'
28
- end
29
- rescue
30
- refresh
31
- end
32
- valid_ticket(@jsapi_ticket_data)
33
- end
34
-
35
- # 获取 jssdk 签名及注册所需其他参数, 返回具有如下结构的 hash:
36
- # params = {
37
- # noncestr: noncestr,
38
- # timestamp: timestamp,
39
- # jsapi_ticket: ticket,
40
- # url: url,
41
- # signature: signature
42
- # }
43
- def signature(url)
44
- timestamp = Time.now.to_i
45
- noncestr = SecureRandom.base64(16)
46
- params = {
47
- noncestr: noncestr,
48
- timestamp: timestamp,
49
- jsapi_ticket: ticket,
50
- url: url
51
- }
52
- pairs = params.keys.sort.map do |key|
53
- "#{key}=#{params[key]}"
54
- end
55
- result = Digest::SHA1.hexdigest pairs.join('&')
56
- params.merge(signature: result)
57
- end
58
-
59
- protected
60
-
61
- def valid_ticket(jsapi_ticket_data)
62
- ticket = jsapi_ticket_data['ticket'] || jsapi_ticket_data[:ticket]
63
- fail "Response didn't have ticket" if ticket.blank?
64
- ticket
65
- end
66
- end
67
- end
@@ -1,13 +0,0 @@
1
- require 'wechat/jsapi_base'
2
-
3
- module Wechat
4
- class JsapiTicket < JsapiBase
5
- # refresh jsapi ticket
6
- def refresh
7
- data = client.get('ticket/getticket', params: { access_token: access_token.token, type: 'jsapi' })
8
- data.merge!('created_at'.freeze => Time.now.to_i)
9
- File.open(jsapi_ticket_file, 'w') { |f| f.write(data.to_json) } if valid_ticket(data)
10
- @jsapi_ticket_data = data
11
- end
12
- end
13
- end