weixin_rails_middleware 1.2.6 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|