wechat 0.6.8 → 0.6.9

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 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