weixin_rails_middleware 1.2.6 → 1.3.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/app/controllers/weixin_rails_middleware/weixin_controller.rb +22 -3
- data/lib/generators/templates/add_encrypt_message_config_migration.rb +14 -0
- data/lib/generators/templates/install_weixin_rails_middleware.rb +4 -0
- data/lib/generators/templates/weixin_controller.rb +51 -53
- data/lib/generators/weixin_rails_middleware/encrypt_migration_generator.rb +35 -0
- data/lib/weixin_rails_middleware/adapter/multiple_public_account.rb +8 -1
- data/lib/weixin_rails_middleware/adapter/single_public_account.rb +10 -1
- data/lib/weixin_rails_middleware/adapter/weixin_adapter.rb +6 -4
- data/lib/weixin_rails_middleware/configuration.rb +8 -6
- data/lib/weixin_rails_middleware/helpers/pkcs7_encoder.rb +28 -0
- data/lib/weixin_rails_middleware/helpers/prpcrypt.rb +48 -0
- data/lib/weixin_rails_middleware/helpers/reply_weixin_message_helper.rb +34 -8
- data/lib/weixin_rails_middleware/models/encrypt_message.rb +24 -0
- data/lib/weixin_rails_middleware/models/message.rb +1 -6
- data/lib/weixin_rails_middleware/version.rb +1 -1
- data/lib/weixin_rails_middleware.rb +9 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0d0b6af708c134cb59378358bbe18334a771f50
|
4
|
+
data.tar.gz: 5f1a555b56fe4be9a1a80405d58664fe0cbd6e3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bb09dd78fad486410742f72691f1411ba85197faa672c1f9a599f3cc6aaad85c8f65fd6b62832ba9fa687c466bcbe4b2c711cbf779f68e1837e1046edd5641d
|
7
|
+
data.tar.gz: 76096e39e64335bb77941cd429120d913a991b509816457d3faf5debc08b14dcbf681b9e8a667c1fff72723480cf89112fac248f382fdbdf6d3e7ba8af6296e1
|
@@ -3,6 +3,7 @@ module WeixinRailsMiddleware
|
|
3
3
|
include ReplyWeixinMessageHelper
|
4
4
|
|
5
5
|
skip_before_filter :verify_authenticity_token
|
6
|
+
before_filter :check_is_encrypt, only: [:index, :reply]
|
6
7
|
before_filter :initialize_adapter, :check_weixin_legality, only: [:index, :reply]
|
7
8
|
before_filter :set_weixin_public_account, :set_weixin_message, only: :reply
|
8
9
|
before_filter :set_keyword, only: :reply
|
@@ -15,6 +16,15 @@ module WeixinRailsMiddleware
|
|
15
16
|
|
16
17
|
protected
|
17
18
|
|
19
|
+
# 如果url上无encrypt_type或者其值为raw,则回复明文,否则按照上述的加密算法加密回复密文。
|
20
|
+
def check_is_encrypt
|
21
|
+
if params[:encrypt_type].blank? || params[:encrypt_type] == "raw"
|
22
|
+
@is_encrypt = false
|
23
|
+
else
|
24
|
+
@is_encrypt = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
18
28
|
def initialize_adapter
|
19
29
|
@weixin_adapter ||= WexinAdapter.init_with(params)
|
20
30
|
end
|
@@ -33,13 +43,22 @@ module WeixinRailsMiddleware
|
|
33
43
|
end
|
34
44
|
|
35
45
|
def set_weixin_message
|
46
|
+
param_xml = request.body.read
|
47
|
+
if @is_encrypt
|
48
|
+
hash = MultiXml.parse(param_xml)['xml']
|
49
|
+
@body_xml = OpenStruct.new(hash)
|
50
|
+
param_xml = Prpcrypt.decrypt(@weixin_public_account.aes_key,
|
51
|
+
@body_xml.Encrypt,
|
52
|
+
@weixin_public_account.app_id
|
53
|
+
)[0]
|
54
|
+
end
|
36
55
|
# Get the current weixin message
|
37
|
-
@weixin_message ||= Message.factory(
|
56
|
+
@weixin_message ||= Message.factory(param_xml)
|
38
57
|
end
|
39
58
|
|
40
59
|
def set_keyword
|
41
|
-
@keyword = @weixin_message.Content
|
42
|
-
@weixin_message.EventKey
|
60
|
+
@keyword = @weixin_message.Content || # 文本消息
|
61
|
+
@weixin_message.EventKey || # 事件推送
|
43
62
|
@weixin_message.Recognition # 接收语音识别结果
|
44
63
|
end
|
45
64
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class AddEncryptMessageConfigColumnsTo<%= table_name.camelize %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
change_table(:<%= table_name %>) do |t|
|
4
|
+
t.string :encoding_aes_key, limit: 43
|
5
|
+
t.string :app_id
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
# By default, we don't want to make any assumption about how to roll back a migration when your
|
11
|
+
# model already existed. Please edit below which fields you would like to remove in this migration.
|
12
|
+
raise ActiveRecord::IrreversibleMigration
|
13
|
+
end
|
14
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
# Use this hook to configure WeixinRailsMiddleware bahaviors.
|
2
3
|
WeixinRailsMiddleware.configure do |config|
|
3
4
|
|
@@ -15,6 +16,9 @@ WeixinRailsMiddleware.configure do |config|
|
|
15
16
|
# config.weixin_token_string = '<%= SecureRandom.hex(12) %>'
|
16
17
|
# using to weixin server url to validate the token can be trusted.
|
17
18
|
# config.weixin_secret_string = '<%= WeiXinUniqueToken.generate(generator: :urlsafe_base64, size: 24) %>'
|
19
|
+
# 加密配置,如果需要加密,配置以下参数
|
20
|
+
# config.encoding_aes_key = '<%= WeiXinUniqueToken.generate(generator: :hex, size: 22)[1..43] %>'
|
21
|
+
# config.app_id = "your app id"
|
18
22
|
|
19
23
|
## You can custom your adapter to validate your weixin account ##
|
20
24
|
# Wiki https://github.com/lanrion/weixin_rails_middleware/wiki/Custom-Adapter
|
@@ -68,65 +68,63 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
68
68
|
send("handle_#{event_type.downcase}_event")
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# 扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送
|
77
|
-
return reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
78
|
-
end
|
79
|
-
reply_text_message("关注公众账号")
|
71
|
+
# 关注公众账号
|
72
|
+
def handle_subscribe_event
|
73
|
+
if @keyword.present?
|
74
|
+
# 扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送
|
75
|
+
return reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
80
76
|
end
|
77
|
+
reply_text_message("关注公众账号")
|
78
|
+
end
|
81
79
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
# 取消关注
|
81
|
+
def handle_unsubscribe_event
|
82
|
+
Rails.logger.info("取消关注")
|
83
|
+
end
|
86
84
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
85
|
+
# 扫描带参数二维码事件: 2. 用户已关注时的事件推送
|
86
|
+
def handle_scan_event
|
87
|
+
reply_text_message("扫描带参数二维码事件: 2. 用户已关注时的事件推送, keyword: #{@keyword}")
|
88
|
+
end
|
91
89
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
def handle_location_event # 上报地理位置事件
|
91
|
+
@lat = @weixin_message.Latitude
|
92
|
+
@lgt = @weixin_message.Longitude
|
93
|
+
@precision = @weixin_message.Precision
|
94
|
+
reply_text_message("Your Location: #{@lat}, #{@lgt}, #{@precision}")
|
95
|
+
end
|
98
96
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
97
|
+
# 点击菜单拉取消息时的事件推送
|
98
|
+
def handle_click_event
|
99
|
+
reply_text_message("你点击了: #{@keyword}")
|
100
|
+
end
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
# 点击菜单跳转链接时的事件推送
|
103
|
+
def handle_view_event
|
104
|
+
Rails.logger.info("你点击了: #{@keyword}")
|
105
|
+
end
|
108
106
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
107
|
+
# 帮助文档: https://github.com/lanrion/weixin_authorize/issues/22
|
108
|
+
|
109
|
+
# 由于群发任务提交后,群发任务可能在一定时间后才完成,因此,群发接口调用时,仅会给出群发任务是否提交成功的提示,若群发任务提交成功,则在群发任务结束时,会向开发者在公众平台填写的开发者URL(callback URL)推送事件。
|
110
|
+
|
111
|
+
# 推送的XML结构如下(发送成功时):
|
112
|
+
|
113
|
+
# <xml>
|
114
|
+
# <ToUserName><![CDATA[gh_3e8adccde292]]></ToUserName>
|
115
|
+
# <FromUserName><![CDATA[oR5Gjjl_eiZoUpGozMo7dbBJ362A]]></FromUserName>
|
116
|
+
# <CreateTime>1394524295</CreateTime>
|
117
|
+
# <MsgType><![CDATA[event]]></MsgType>
|
118
|
+
# <Event><![CDATA[MASSSENDJOBFINISH]]></Event>
|
119
|
+
# <MsgID>1988</MsgID>
|
120
|
+
# <Status><![CDATA[sendsuccess]]></Status>
|
121
|
+
# <TotalCount>100</TotalCount>
|
122
|
+
# <FilterCount>80</FilterCount>
|
123
|
+
# <SentCount>75</SentCount>
|
124
|
+
# <ErrorCount>5</ErrorCount>
|
125
|
+
# </xml>
|
126
|
+
def handle_masssendjobfinish_event
|
127
|
+
Rails.logger.info("回调事件处理")
|
128
|
+
end
|
131
129
|
|
132
130
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module WeixinRailsMiddleware
|
4
|
+
module Generators
|
5
|
+
class EncryptMigrationGenerator < ActiveRecord::Generators::Base
|
6
|
+
source_root File.expand_path('../../templates', __FILE__)
|
7
|
+
|
8
|
+
desc 'Adds encrypt message config for your application.'
|
9
|
+
def create_migration_file
|
10
|
+
if !migration_exists?(table_name)
|
11
|
+
migration_template "add_encrypt_message_config_migration.rb", "db/migrate/add_encrypt_message_config_columns_to_#{plural_name}.rb"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def model_exists?
|
18
|
+
File.exists?(File.join(destination_root, model_path))
|
19
|
+
end
|
20
|
+
|
21
|
+
def model_path
|
22
|
+
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
def migration_exists?(table_name)
|
26
|
+
Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_encrypt_message_config_columns_to_#{table_name}.rb/).first
|
27
|
+
end
|
28
|
+
|
29
|
+
def migration_path
|
30
|
+
@migration_path ||= File.join("db", "migrate")
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -16,8 +16,15 @@ module WeixinRailsMiddleware
|
|
16
16
|
current_weixin_public_account.try(DEFAULT_TOKEN_COLUMN_NAME)
|
17
17
|
end
|
18
18
|
|
19
|
+
# TODO: handle Exception
|
19
20
|
def current_weixin_public_account
|
20
|
-
self.class.token_model_class.where("#{DEFAULT_WEIXIN_SECRET_KEY}" => weixin_secret_key).first
|
21
|
+
@current_weixin_public_account ||= self.class.token_model_class.where("#{DEFAULT_WEIXIN_SECRET_KEY}" => weixin_secret_key).first
|
22
|
+
@current_weixin_public_account.instance_eval do
|
23
|
+
def aes_key
|
24
|
+
WexinAdapter.decode64(encoding_aes_key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@current_weixin_public_account
|
21
28
|
end
|
22
29
|
|
23
30
|
def error_msg
|
@@ -16,7 +16,16 @@ module WeixinRailsMiddleware
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def current_weixin_public_account
|
19
|
-
|
19
|
+
@current_weixin_public_account ||= OpenStruct.new(
|
20
|
+
weixin_secret_string: self.class.weixin_secret_string,
|
21
|
+
weixin_token_string: self.class.weixin_token_string,
|
22
|
+
app_id: self.class.app_id)
|
23
|
+
@current_weixin_public_account.instance_eval do
|
24
|
+
def aes_key
|
25
|
+
WexinAdapter.decode64(WexinAdapter.encoding_aes_key)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@current_weixin_public_account
|
20
29
|
end
|
21
30
|
|
22
31
|
def error_msg
|
@@ -10,7 +10,6 @@ module WeixinRailsMiddleware
|
|
10
10
|
@weixin_secret_key = weixin_params[:weixin_secret_key]
|
11
11
|
# 以下参数为什么加空字符串默认值的原因:
|
12
12
|
# 微信偶尔会再重新发一次get请求,但是不会带上signature,timestamp,nonce的参数
|
13
|
-
# 一个预防措施吧。
|
14
13
|
@signature = weixin_params[:signature] || ''
|
15
14
|
@timestamp = weixin_params[:timestamp] || ''
|
16
15
|
@nonce = weixin_params[:nonce] || ''
|
@@ -32,7 +31,7 @@ module WeixinRailsMiddleware
|
|
32
31
|
end
|
33
32
|
|
34
33
|
def check_weixin_legality
|
35
|
-
return render_authorize_result(
|
34
|
+
return render_authorize_result(401, self.class.error_msg) if !is_signature_valid?
|
36
35
|
render_authorize_result(200, echostr, true)
|
37
36
|
end
|
38
37
|
|
@@ -59,12 +58,16 @@ module WeixinRailsMiddleware
|
|
59
58
|
def error_msg
|
60
59
|
"#{__FILE__}:#{__LINE__}: Weixin signature NotMatch"
|
61
60
|
end
|
61
|
+
|
62
|
+
def decode64(encoding_aes)
|
63
|
+
Base64.decode64("#{encoding_aes}=")
|
64
|
+
end
|
62
65
|
end
|
63
66
|
|
64
67
|
private
|
65
68
|
|
66
69
|
# render weixin server authorize results
|
67
|
-
def render_authorize_result(status=
|
70
|
+
def render_authorize_result(status=401, text=nil, valid=false)
|
68
71
|
text = text || error_msg
|
69
72
|
Rails.logger.error(text) if status != 200
|
70
73
|
{text: text, status: status, valid: valid}
|
@@ -73,6 +76,5 @@ module WeixinRailsMiddleware
|
|
73
76
|
def error_msg
|
74
77
|
self.class.error_msg
|
75
78
|
end
|
76
|
-
|
77
79
|
end
|
78
80
|
end
|
@@ -17,24 +17,26 @@ module WeixinRailsMiddleware
|
|
17
17
|
class Configuration
|
18
18
|
attr_accessor :public_account_class
|
19
19
|
attr_accessor :weixin_secret_string, :weixin_token_string
|
20
|
+
# 加密参数配置
|
21
|
+
attr_accessor :encoding_aes_key, :app_id
|
22
|
+
|
23
|
+
# 自定义场景
|
20
24
|
attr_accessor :custom_adapter
|
21
25
|
end
|
22
26
|
|
23
27
|
module ConfigurationHelpers
|
24
28
|
extend ActiveSupport::Concern
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
[:weixin_secret_string, :weixin_token_string, :encoding_aes_key, :app_id].each do |attr_name|
|
31
|
+
define_method attr_name do
|
32
|
+
WeixinRailsMiddleware.config.send(attr_name).to_s
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
def token_model
|
31
37
|
@public_account_class ||= WeixinRailsMiddleware.config.public_account_class
|
32
38
|
end
|
33
39
|
|
34
|
-
def weixin_secret_string
|
35
|
-
@weixin_secret_string ||= WeixinRailsMiddleware.config.weixin_secret_string.to_s
|
36
|
-
end
|
37
|
-
|
38
40
|
def token_model_class
|
39
41
|
if token_model.blank?
|
40
42
|
raise "You need to config `public_account_class` in 'config/initializers/weixin_rails_middleware.rb'"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WeixinRailsMiddleware
|
4
|
+
module PKCS7Encoder
|
5
|
+
extend self
|
6
|
+
|
7
|
+
BLOCK_SIZE = 32
|
8
|
+
|
9
|
+
def decode(text)
|
10
|
+
pad = text[-1].ord
|
11
|
+
pad = 0 if (pad < 1 || pad > BLOCK_SIZE)
|
12
|
+
size = text.size - pad
|
13
|
+
text[0...size]
|
14
|
+
end
|
15
|
+
|
16
|
+
# 对需要加密的明文进行填充补位
|
17
|
+
# 返回补齐明文字符串
|
18
|
+
def encode(text)
|
19
|
+
# 计算需要填充的位数
|
20
|
+
amount_to_pad = BLOCK_SIZE - (text.length % BLOCK_SIZE)
|
21
|
+
amount_to_pad = BLOCK_SIZE if amount_to_pad == 0
|
22
|
+
# 获得补位所用的字符
|
23
|
+
pad_chr = amount_to_pad.chr
|
24
|
+
"#{text}#{pad_chr * amount_to_pad}"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "weixin_rails_middleware/helpers/pkcs7_encoder"
|
3
|
+
module WeixinRailsMiddleware
|
4
|
+
module Prpcrypt
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# 对密文进行解密.
|
8
|
+
# text 需要解密的密文
|
9
|
+
def decrypt(aes_key, text, app_id)
|
10
|
+
status = 200
|
11
|
+
text = Base64.decode64(text)
|
12
|
+
text = handle_cipher(:decrypt, aes_key, text)
|
13
|
+
result = PKCS7Encoder.decode(text)
|
14
|
+
content = result[16...result.length]
|
15
|
+
len_list = content[0...4].unpack("N")
|
16
|
+
xml_len = len_list[0]
|
17
|
+
xml_content = content[4...4 + xml_len]
|
18
|
+
from_app_id = content[xml_len + 4...content.size]
|
19
|
+
# TODO: refactor
|
20
|
+
if app_id != from_app_id
|
21
|
+
Rails.logger.debug("#{__FILE__}:#{__LINE__} Failure because app_id != from_app_id")
|
22
|
+
status = 401
|
23
|
+
end
|
24
|
+
[xml_content, status]
|
25
|
+
end
|
26
|
+
|
27
|
+
# 加密
|
28
|
+
def encrypt(aes_key, text, app_id)
|
29
|
+
text = text.force_encoding("ASCII-8BIT")
|
30
|
+
random = SecureRandom.hex(8)
|
31
|
+
msg_len = [text.length].pack("N")
|
32
|
+
text = "#{random}#{msg_len}#{text}#{app_id}"
|
33
|
+
text = PKCS7Encoder.encode(text)
|
34
|
+
text = handle_cipher(:encrypt, aes_key, text)
|
35
|
+
Base64.encode64(text)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def handle_cipher(action, aes_key, text)
|
40
|
+
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
41
|
+
cipher.send(action)
|
42
|
+
cipher.padding = 0
|
43
|
+
cipher.key = aes_key
|
44
|
+
cipher.iv = aes_key[0...16]
|
45
|
+
cipher.update(text) + cipher.final
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -9,7 +9,7 @@ module WeixinRailsMiddleware
|
|
9
9
|
message.FromUserName = from || @weixin_message.ToUserName
|
10
10
|
message.ToUserName = to || @weixin_message.FromUserName
|
11
11
|
message.Content = content
|
12
|
-
message.to_xml
|
12
|
+
encrypt_message message.to_xml
|
13
13
|
end
|
14
14
|
|
15
15
|
def generate_music(title, desc, music_url, hq_music_url)
|
@@ -27,7 +27,7 @@ module WeixinRailsMiddleware
|
|
27
27
|
message.FromUserName = from || @weixin_message.ToUserName
|
28
28
|
message.ToUserName = to || @weixin_message.FromUserName
|
29
29
|
message.Music = music
|
30
|
-
message.to_xml
|
30
|
+
encrypt_message message.to_xml
|
31
31
|
end
|
32
32
|
|
33
33
|
def generate_article(title, desc, pic_url, link_url)
|
@@ -46,7 +46,7 @@ module WeixinRailsMiddleware
|
|
46
46
|
message.ToUserName = to || @weixin_message.FromUserName
|
47
47
|
message.Articles = articles
|
48
48
|
message.ArticleCount = articles.count
|
49
|
-
message.to_xml
|
49
|
+
encrypt_message message.to_xml
|
50
50
|
end
|
51
51
|
|
52
52
|
def generate_video(media_id, desc, title)
|
@@ -74,7 +74,7 @@ module WeixinRailsMiddleware
|
|
74
74
|
message.FromUserName = from || @weixin_message.ToUserName
|
75
75
|
message.ToUserName = to || @weixin_message.FromUserName
|
76
76
|
message.Video = video
|
77
|
-
message.to_xml
|
77
|
+
encrypt_message message.to_xml
|
78
78
|
end
|
79
79
|
|
80
80
|
def generate_voice(media_id)
|
@@ -88,7 +88,7 @@ module WeixinRailsMiddleware
|
|
88
88
|
message.FromUserName = from || @weixin_message.ToUserName
|
89
89
|
message.ToUserName = to || @weixin_message.FromUserName
|
90
90
|
message.Voice = voice
|
91
|
-
message.to_xml
|
91
|
+
encrypt_message message.to_xml
|
92
92
|
end
|
93
93
|
|
94
94
|
def generate_image(media_id)
|
@@ -102,15 +102,41 @@ module WeixinRailsMiddleware
|
|
102
102
|
message.FromUserName = from || @weixin_message.ToUserName
|
103
103
|
message.ToUserName = to || @weixin_message.FromUserName
|
104
104
|
message.Image = image
|
105
|
-
message.to_xml
|
105
|
+
encrypt_message message.to_xml
|
106
106
|
end
|
107
107
|
|
108
|
-
|
109
108
|
def reply_transfer_customer_service_message(from=nil, to=nil)
|
110
109
|
message = TransferCustomerServiceReplyMessage.new
|
111
110
|
message.FromUserName = from || @weixin_message.ToUserName
|
112
111
|
message.ToUserName = to || @weixin_message.FromUserName
|
113
|
-
message.to_xml
|
112
|
+
encrypt_message message.to_xml
|
114
113
|
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def encrypt_message(msg_xml)
|
118
|
+
return msg_xml if !@is_encrypt
|
119
|
+
# 加密回复的XML
|
120
|
+
encrypt_xml = Prpcrypt.encrypt(@weixin_public_account.aes_key, msg_xml, @weixin_public_account.app_id).gsub("\n","")
|
121
|
+
# 标准的回包
|
122
|
+
generate_encrypt_message(encrypt_xml)
|
123
|
+
end
|
124
|
+
|
125
|
+
def generate_encrypt_message(encrypt_xml)
|
126
|
+
msg = EncryptMessage.new
|
127
|
+
msg.Encrypt = encrypt_xml
|
128
|
+
msg.TimeStamp = Time.now.to_i.to_s
|
129
|
+
msg.Nonce = SecureRandom.hex(8)
|
130
|
+
msg.MsgSignature = generate_msg_signature(encrypt_xml, msg)
|
131
|
+
msg.to_xml
|
132
|
+
end
|
133
|
+
|
134
|
+
# dev_msg_signature=sha1(sort(token、timestamp、nonce、msg_encrypt))
|
135
|
+
# 生成企业签名
|
136
|
+
def generate_msg_signature(encrypt_msg, msg)
|
137
|
+
sort_params = [encrypt_msg, @weixin_adapter.current_weixin_token,
|
138
|
+
msg.TimeStamp, msg.Nonce].sort.join
|
139
|
+
Digest::SHA1.hexdigest(sort_params)
|
140
|
+
end
|
115
141
|
end
|
116
142
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# 标准的回包
|
3
|
+
# <xml>
|
4
|
+
# <Encrypt><![CDATA[msg_encrypt]]></Encrypt>
|
5
|
+
# <MsgSignature><![CDATA[msg_signature]]></MsgSignature>
|
6
|
+
# <TimeStamp>timestamp</TimeStamp>
|
7
|
+
# <Nonce><![CDATA[nonce]]></Nonce>
|
8
|
+
# </xml>
|
9
|
+
|
10
|
+
module WeixinRailsMiddleware
|
11
|
+
class EncryptMessage
|
12
|
+
include ROXML
|
13
|
+
xml_name :xml
|
14
|
+
|
15
|
+
xml_accessor :Encrypt, :cdata => true
|
16
|
+
xml_accessor :Nonce, :cdata => true
|
17
|
+
xml_accessor :TimeStamp, :as => Integer
|
18
|
+
xml_accessor :MsgSignature, :cdata => true
|
19
|
+
|
20
|
+
def to_xml
|
21
|
+
super.to_xml(:encoding => 'UTF-8', :indent => 0, :save_with => 0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,9 +1,4 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
# ref: https://github.com/wolfg1969/rack-weixin/lib/weixin/model.rb
|
3
|
-
require 'roxml'
|
4
|
-
require 'multi_xml'
|
5
|
-
require 'ostruct'
|
6
|
-
|
7
2
|
# multi_xml will use Nokogiri if it is available
|
8
3
|
MultiXml.parser = :nokogiri
|
9
4
|
|
@@ -45,7 +40,7 @@ module WeixinRailsMiddleware
|
|
45
40
|
when 'video'
|
46
41
|
VideoMessage.new(hash)
|
47
42
|
else
|
48
|
-
raise ArgumentError, 'Unknown Message'
|
43
|
+
raise ArgumentError, 'Unknown Weixin Message'
|
49
44
|
end
|
50
45
|
end
|
51
46
|
|
@@ -1,7 +1,16 @@
|
|
1
|
+
require 'roxml'
|
2
|
+
require 'multi_xml'
|
3
|
+
require 'ostruct'
|
4
|
+
|
1
5
|
require "weixin_rails_middleware/configuration"
|
2
6
|
require "weixin_rails_middleware/engine"
|
7
|
+
|
8
|
+
require "weixin_rails_middleware/models/encrypt_message"
|
3
9
|
require "weixin_rails_middleware/models/message"
|
4
10
|
require "weixin_rails_middleware/models/reply_message"
|
11
|
+
|
12
|
+
require "weixin_rails_middleware/helpers/prpcrypt"
|
13
|
+
|
5
14
|
require "weixin_rails_middleware/helpers/reply_weixin_message_helper"
|
6
15
|
require "weixin_rails_middleware/helpers/unique_token_helper"
|
7
16
|
require "weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: weixin_rails_middleware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lanrion
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -91,9 +91,11 @@ files:
|
|
91
91
|
- Rakefile
|
92
92
|
- app/controllers/weixin_rails_middleware/weixin_controller.rb
|
93
93
|
- config/routes.rb
|
94
|
+
- lib/generators/templates/add_encrypt_message_config_migration.rb
|
94
95
|
- lib/generators/templates/add_weixin_secret_key_and_weixin_token_migration.rb
|
95
96
|
- lib/generators/templates/install_weixin_rails_middleware.rb
|
96
97
|
- lib/generators/templates/weixin_controller.rb
|
98
|
+
- lib/generators/weixin_rails_middleware/encrypt_migration_generator.rb
|
97
99
|
- lib/generators/weixin_rails_middleware/install_generator.rb
|
98
100
|
- lib/generators/weixin_rails_middleware/migration_generator.rb
|
99
101
|
- lib/weixin_rails_middleware.rb
|
@@ -103,8 +105,11 @@ files:
|
|
103
105
|
- lib/weixin_rails_middleware/configuration.rb
|
104
106
|
- lib/weixin_rails_middleware/engine.rb
|
105
107
|
- lib/weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key.rb
|
108
|
+
- lib/weixin_rails_middleware/helpers/pkcs7_encoder.rb
|
109
|
+
- lib/weixin_rails_middleware/helpers/prpcrypt.rb
|
106
110
|
- lib/weixin_rails_middleware/helpers/reply_weixin_message_helper.rb
|
107
111
|
- lib/weixin_rails_middleware/helpers/unique_token_helper.rb
|
112
|
+
- lib/weixin_rails_middleware/models/encrypt_message.rb
|
108
113
|
- lib/weixin_rails_middleware/models/message.rb
|
109
114
|
- lib/weixin_rails_middleware/models/reply_message.rb
|
110
115
|
- lib/weixin_rails_middleware/version.rb
|