yol_sso 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 061fba38ddccfb3737e87608089ff75e37b7b0288e0b34b150b6011b2dfbbf40
4
+ data.tar.gz: 36924d8292b0d51261fb5d71800c3a1fc4790f57f65f297e85c0ac4274337ee6
5
+ SHA512:
6
+ metadata.gz: 4aa0e69e03cf2a4951b73b5019234ea9f3cf455879582ef4f122c6c87f30e2860b7143f3fa9e3e49ebf6aefaaafafc0f12dd3e69d157d2c0a2a4d26630ff02d7
7
+ data.tar.gz: 9f5bf41f3f012d059af1c7dc64f19de2a56fc9fcaef5ac4c612478781140514a46f797953ccc90afb27bfd241289f0315cefa154bc4634e92dd3bc01f397f8f9
data/.DS_Store ADDED
Binary file
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yol_qy_weixin.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ yol_sso (0.0.1)
5
+ multi_xml
6
+ nokogiri
7
+ roxml
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (6.0.3.2)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ zeitwerk (~> 2.2, >= 2.2.2)
18
+ concurrent-ruby (1.1.9)
19
+ i18n (1.8.10)
20
+ concurrent-ruby (~> 1.0)
21
+ minitest (5.14.4)
22
+ multi_xml (0.6.0)
23
+ nokogiri (1.11.7-x86_64-darwin)
24
+ racc (~> 1.4)
25
+ racc (1.5.2)
26
+ rake (13.0.1)
27
+ roxml (4.1.1)
28
+ activesupport (>= 4.0)
29
+ nokogiri (>= 1.3.3)
30
+ thread_safe (0.3.6)
31
+ tzinfo (1.2.9)
32
+ thread_safe (~> 0.1)
33
+ zeitwerk (2.4.0)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ bundler
40
+ rake
41
+ yol_sso!
42
+
43
+ BUNDLED WITH
44
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,371 @@
1
+ # Sso
2
+
3
+ This project rocks and uses MIT-LICENSE.
4
+
5
+ https://rubygems.org/gems/yol_qy_weixin
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/yol_qy_weixin.svg)](http://badge.fury.io/rb/yol_qy_weixin)
8
+
9
+ **有问题请及时提issue**
10
+
11
+ ```ruby
12
+ gem "yol_qy_weixin", git: "https://github.com/luojie2019/yol_qy_weixin.git"
13
+ ```
14
+
15
+ # 配置
16
+
17
+ ## 安装依赖Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'yol_qy_weixin'
23
+ ```
24
+ ## 配置 corpid secret
25
+
26
+ ```ruby
27
+ # 目录
28
+
29
+ file: your_project/config/qy_weixin.yml
30
+
31
+ .your_project/
32
+ ├── app
33
+ ├── bin
34
+ ├── config
35
+ │ ├── redis.yml
36
+ │ ├── database.yml
37
+ │ ├── qy_weixin.yml
38
+ ```
39
+
40
+ ```yml
41
+ defaults: &defaults
42
+ corpid: '1**'
43
+ secret: '2**'
44
+
45
+ development: &development
46
+ <<: *defaults
47
+
48
+ test:
49
+ <<: *defaults
50
+
51
+ production:
52
+ corpid: <%= ENV.fetch('QY_WEIXIN_CORPID') { '1**'' } %>
53
+ secret: <%= ENV.fetch('QY_WEIXIN_SECRET') { '2**'' } %>
54
+ ```
55
+
56
+ **说明:考虑access_token需要缓存,redis配置请参考官方文档 https://github.com/redis/redis-rb/blob/master/README.md**
57
+
58
+ ## 读取配置
59
+ ```ruby
60
+ # 读取qy_weixin.yml配置
61
+ qy_weixin_config = YAML::load(ERB.new(File.read("#{Rails.root}/config/qy_weixin.yml")).result)[Rails.env]
62
+ ```
63
+ 如果你是在Rails框架下,也可以使用Settingslogic读取yml配置:
64
+ ```ruby
65
+ # 引用gem
66
+ gem 'settingslogic', '2.0.9'
67
+
68
+ # your_project/app/settings/weixin_setting.rb
69
+ class WeixinSetting < Settingslogic
70
+ source "#{Rails.root}/config/weixin.yml"
71
+ namespace Rails.env
72
+ end
73
+
74
+ corpid = WeixinSetting.corpid
75
+ corp_secret = WeixinSetting.secret
76
+ ```
77
+
78
+ ## 实例对象
79
+
80
+ ```ruby
81
+ # 目录 file: your_project/config/initializers/qy_weixin.rb
82
+
83
+ QyWexinClient = YolQyWeixin::Client.new(
84
+ corpid: qy_weixin_config["corpid"],
85
+ secret: qy_weixin_config["secret"],
86
+ redis: RedisClient
87
+ )
88
+ ```
89
+
90
+ **说明:RedisClient为redis实例,如果没有配置可传nil,建议使用redis,考虑到access_token获取次数限制;**
91
+
92
+ # 基本用法
93
+
94
+ 如果需要获取的 access_token
95
+
96
+ ```ruby
97
+ access_token = QyWexinClient.get_access_token
98
+ # 返回参考企业微信官方文档:https://work.weixin.qq.com/api/doc/90000/90135/91039
99
+ ```
100
+
101
+ ## 部门
102
+
103
+ ```ruby
104
+ 待补充,有需要可提issue到git:https://github.com/luojie2019/yol_qy_weixin.git
105
+ ```
106
+
107
+ ## 成员
108
+
109
+ ```ruby
110
+ # 获取成员信息
111
+ access_token = QyWexinClient.get_user_info(open_id)
112
+ # 返回参考企业微信官方文档:https://open.work.weixin.qq.com/api/doc/90000/90135/90196
113
+
114
+ # 获取反问用户信息
115
+ access_token = QyWexinClient.get_user_id(code)
116
+ # 返回参考企业微信官方文档:https://open.work.weixin.qq.com/api/doc/90000/90135/91707
117
+ ```
118
+
119
+
120
+ ---
121
+
122
+
123
+ 后续功能实现还待优化,有需要可提issue到git:https://github.com/luojie2019/yol_qy_weixin.git
124
+
125
+ ## 标签
126
+
127
+ ```ruby
128
+ group_client.tag.create(name)
129
+ group_client.tag.update(id, name)
130
+ group_client.tag.delete(id)
131
+ group_client.tag.get(id)
132
+ group_client.tag.add_tag_users(id, user_ids)
133
+ group_client.tag.delete_tag_users(id, user_ids)
134
+ group_client.tag.list
135
+ ```
136
+
137
+ ## 自定义菜单
138
+
139
+ menu_json的生成方法请参考:
140
+ https://github.com/lanrion/weixin_rails_middleware/wiki/DIY-menu
141
+
142
+ ```ruby
143
+ group_client.menu.create(menu_json, app_id)
144
+ group_client.menu.delete(app_id)
145
+ group_client.menu.get(app_id)
146
+ ```
147
+
148
+ ## Oauth2用法
149
+
150
+ 先要配置你应用的 可信域名 `2458023e.ngrok.com`
151
+ state 为开发者自定义参数,可选
152
+
153
+ ```ruby
154
+ # 生成授权url
155
+ group_client.oauth.authorize_url("http://2458023e.ngrok.com", "state")
156
+
157
+ # 获取code后,获取用户信息
158
+ # app_id: 跳转链接时所在的企业应用ID
159
+ group_client.oauth.get_user_info("code", "app_id")
160
+ ```
161
+
162
+ ## 发送消息
163
+
164
+ ```ruby
165
+ # params: (users, parties, tags, agent_id, content, safe=0)
166
+ # users, parties, tags 如果是多个用户,传数组,如果是全部,则直接传 "@all"
167
+ group_client.message.send_text("@all", "@all", "@all", app_id, text_message)
168
+ ```
169
+ **其他发送消息方法请查看 api/message.rb**
170
+
171
+ ## 上传多媒体文件
172
+ ```ruby
173
+ # params: media, media_type
174
+ group_client.media.upload(image_jpg_file, "image")
175
+
176
+ # 获取下载链接
177
+ # 返回一个URL,请开发者自行使用此url下载
178
+ group_client.media.get_media_by_id(media_id)
179
+
180
+ # 上传永久图文素材
181
+ # articles 为图文列表:
182
+ {
183
+ "title": "Title01",
184
+ "thumb_media_id": "2-G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0",
185
+ "author": "zs",
186
+ "content_source_url": "",
187
+ "content": "Content001",
188
+ "digest": "airticle01",
189
+ "show_cover_pic": "0"
190
+ }
191
+ group_client.material.add_mpnews(agent_id, articles)
192
+
193
+ # 更新图文素材
194
+ group_client.material.update_mpnews(agent_id, media_id, articles=[])
195
+
196
+ # 上传其他类型永久素材
197
+ # type: "image", "voice", "video", "file"
198
+ # file: File
199
+ group_client.material.add_material(agent_id, type, file)
200
+
201
+ # 删除永久素材
202
+ group_client.material.del(agent_id, media_id)
203
+
204
+ # 获取素材总数
205
+ group_client.material.get_count(agent_id)
206
+
207
+ # 获取素材列表
208
+ group_client.material.list(agent_id, type, offset, count=20)
209
+ ```
210
+
211
+ ## 第三方应用
212
+
213
+ 这里特别注意:保留 suite_access_token的cache是直接利用了前文配置的cache_store缓存。
214
+
215
+ ### api 使用介绍
216
+
217
+ ```ruby
218
+ suite_api = QyWechatApi::Suite.service(suite_id, suite_secret, suite_ticket)
219
+
220
+ # 获取预授权码
221
+ suite_api.get_pre_auth_code(appid=[])
222
+
223
+ # 获取企业号的永久授权码
224
+ suite_api.get_permanent_code(auth_code)
225
+
226
+ # 获取企业号的授权信息
227
+ suite_api.get_auth_info(auth_corpid, code)
228
+
229
+ # 获取企业号应用
230
+ suite_api.get_agent(auth_corpid, code, agent_id)
231
+
232
+ # 设置授权方的企业应用的选项设置信息
233
+ suite_api.set_agent(auth_corpid, permanent_code, agent_info)
234
+
235
+ # 调用企业接口所需的access_token
236
+ suite_api.get_corp_token(auth_corpid, permanent_code)
237
+
238
+ # 生成授权URL
239
+ suite_api.auth_url(code, uri, state="suite")
240
+
241
+ ```
242
+
243
+ ## 企业号登录授权
244
+
245
+ ```ruby
246
+ # 获取登录授权URL
247
+ # state default 'qy_wechat', option
248
+ # 此处授权回调时会传递auth_code、expires_in,auth_code用于get_login_info(获取企业号管理员登录信息)接口使用
249
+ group_client.auth_login.auth_login_url("redirect_uri", "state")
250
+
251
+ # 获取应用提供商凭证
252
+ # provider_secret:提供商的secret,在提供商管理页面可见
253
+ # 此处会返回:provider_access_token(已通过QyWechatApi.cache缓存7100s)
254
+ group_client.auth_login.get_provider_token(provider_secret)
255
+
256
+ # 通过传递provider_access_token,获取企业号管理员登录信息
257
+ group_client.auth_login.get_login_info(auth_code, provider_access_token)
258
+
259
+ # 通过传递provider_secret,获取企业号管理员登录信息
260
+ group_client.auth_login.get_login_info_by_secret(auth_code, provider_secret)
261
+
262
+ # 获取登录企业号官网的url
263
+ group_client.auth_login.get_login_url(ticket, provider_token, target, agentid=nil)
264
+ ```
265
+
266
+ ## 异步任务接口
267
+
268
+ ```ruby
269
+ # 邀请成员关注
270
+ group_client.async_task.invite_user(callback, invite_info={})
271
+ # 增量更新成员
272
+ group_client.async_task.sync_user(callback, media_id)
273
+ # 全量覆盖成员
274
+ group_client.async_task.replace_user(callback, media_id)
275
+ # 全量覆盖部门
276
+ group_client.async_task.replace_party(callback, media_id)
277
+ # 获取异步任务结果
278
+ group_client.async_task.get_result(job_id)
279
+ ```
280
+
281
+ ## 获取js api签名包
282
+ ```ruby
283
+ group_client.sign_package(request.url)
284
+ ```
285
+
286
+ ## 管理企业号应用
287
+
288
+ ```ruby
289
+ # 获取应用概况列表
290
+ group_client.agent.list
291
+
292
+ # 设置企业号应用
293
+ # agentid 企业应用的id
294
+ # report_location_flag 企业应用是否打开地理位置上报 0:不上报;1:进入会话上报;2:持续上报
295
+ # logo_mediaid 企业应用头像的mediaid,通过多媒体接口上传图片获得mediaid,上传后会自动裁剪成方形和圆形两个头像
296
+ # name 企业应用名称
297
+ # description 企业应用详情
298
+ # redirect_domain 企业应用可信域名
299
+ # isreportuser 是否接收用户变更通知。0:不接收;1:接收
300
+ # isreportenter 是否上报用户进入应用事件。0:不接收;1:接收
301
+ group_client.agent.set()
302
+
303
+ ## 获取企业号应用
304
+ group_client.agent.get(agent_id)
305
+ ```
306
+
307
+ ### 应用套件的回调通知处理
308
+
309
+ Wiki: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%9B%9E%E8%B0%83%E5%8D%8F%E8%AE%AE
310
+
311
+ ```ruby
312
+ class QyServicesController < ApplicationController
313
+ skip_before_filter :verify_authenticity_token, only: :receive_ticket
314
+
315
+ # TODO: 需要创建表: suites
316
+ def receive_ticket
317
+ param_xml = request.body.read
318
+ aes_key = "NJgquXf6vnYlGpD5APBqlndAq7Nx8fToiEz5Wbaka47"
319
+ aes_key = Base64.decode64("#{aes_key}=")
320
+ hash = MultiXml.parse(param_xml)['xml']
321
+ @body_xml = OpenStruct.new(hash)
322
+ suite_id = "tj86cd0f5b8f7ce20d"
323
+ content = QyWechat::Prpcrypt.decrypt(aes_key, @body_xml.Encrypt, suite_id)[0]
324
+ hash = MultiXml.parse(content)["xml"]
325
+ Rails.logger.info hash
326
+ render text: "success"
327
+ # {"SuiteId"=>"tj86cd0f5b8f7ce20d",
328
+ # "SuiteTicket"=>"Pb5M0PEQFZSNondlK1K_atu2EoobY9piMcQCdE3URiCG3aTwX5WBTQaSsqCzaD-0",
329
+ # "InfoType"=>"suite_ticket",
330
+ # "TimeStamp"=>"1426988061"}
331
+ end
332
+ end
333
+ ```
334
+
335
+ ### 企业号消息接口
336
+
337
+ Wiki: http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E5%8F%B7%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
338
+
339
+ ```ruby
340
+ group_client.chat.send_single_text(sender, user_id, msg)
341
+ group_client.chat.send_single_image(sender, user_id, media_id)
342
+ group_client.chat.send_single_file(sender, user_id, media_id)
343
+ group_client.chat.send_group_text(sender, chat_id, msg)
344
+ group_client.chat.send_group_image(sender, chat_id, media_id)
345
+ group_client.chat.send_group_file(sender, chat_id, media_id)
346
+ ```
347
+
348
+ ### 企业客服服务
349
+
350
+ Wiki: http://qydev.weixin.qq.com/wiki/index.php?title=企业客服接口说明
351
+
352
+ ```ruby
353
+ # msg_struct请根据文档结构拼接传入
354
+ group_client.kf.send(msg_struct)
355
+ ```
356
+
357
+ ### 企业号摇一摇周边
358
+
359
+ Wiki: http://qydev.weixin.qq.com/wiki/index.php?title=获取设备及用户信息
360
+
361
+ ```ruby
362
+ # 获取设备及用户信息
363
+ # 摇周边业务的ticket,可在摇到的URL中得到,ticket生效时间为30分钟,每一次摇都会重新生成新的ticket
364
+ group_client.get_shake_info(ticket)
365
+ ```
366
+
367
+ ## 捐赠支持
368
+
369
+ 如果你觉得我的gem对你有帮助,欢迎打赏支持,:smile:
370
+
371
+ ![](https://raw.githubusercontent.com/lanrion/my_config/master/imagex/donation_me_wx.jpg)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/yol_sso.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'roxml'
2
+ require 'multi_xml'
3
+ require 'ostruct'
4
+ require 'net/http'
5
+ require 'json'
6
+
7
+ require "yol_sso/version"
8
+
9
+ require "yol_sso/models/configuration"
10
+ require "yol_sso/models/encrypt_message"
11
+ require "yol_sso/helpers/prpcrypt"
12
+
13
+ require "yol_sso/connection"
14
+ require "yol_sso/client"
15
+
16
+ module YolSso
17
+
18
+ class << self
19
+
20
+ # A Sso configuration object. See Sso::Configuration.
21
+ attr_writer :configuration
22
+
23
+ def configure
24
+ yield(configuration)
25
+ end
26
+
27
+ def configuration
28
+ @configuration ||= Configuration.new
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ require "monitor"
2
+ require "redis"
3
+ require 'digest/md5'
4
+ module YolSso
5
+ class Client
6
+
7
+ include Connection::Base
8
+ include Connection::Message
9
+
10
+ attr_accessor :host
11
+
12
+ attr_accessor :agentid
13
+
14
+ def initialize(options = {})
15
+ @host = options[:host] || Sso.configuration.host
16
+ @agentid = options[:agentid] || Sso.configuration.agentid
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/connections/*.rb"].each do |path|
2
+ require path
3
+ end
@@ -0,0 +1,60 @@
1
+ module YolSso
2
+ module Connection
3
+ module Base
4
+ def http_post(url, params)
5
+ uri = URI(url)
6
+ req = Net::HTTP.new(uri.host, uri.port)
7
+ header = {'content-type': 'application/json'}
8
+ req.use_ssl = true if uri.scheme == 'https'
9
+ res = req.post("#{uri.path}?#{uri.query}", params.to_json, header)
10
+ handle_res(res)
11
+ end
12
+
13
+ def http_get(url)
14
+ uri = URI(url)
15
+ req = Net::HTTP.new(uri.host, uri.port)
16
+ req.use_ssl = true if uri.scheme == 'https'
17
+ res = req.get("#{uri.path}?#{uri.query}")
18
+ handle_res(res)
19
+ end
20
+
21
+ def get_access_token
22
+ if redis.nil?
23
+ access_token_res = get_token(corpid, secret)
24
+ access_token = access_token_res["access_token"] rescue nil
25
+ else
26
+ access_token = redis.get("qywx_access_token")
27
+ if access_token.nil?
28
+ access_token_res = get_token(corpid, secret)
29
+ access_token = access_token_res["access_token"] rescue nil
30
+ if access_token.nil?
31
+ raise Exception.new("QyWeixin access token authorize false, corpid: #{corpid}")
32
+ else
33
+ redis.set("qywx_access_token", access_token)
34
+ redis.expire("qywx_access_token", 7200)
35
+ end
36
+ end
37
+ end
38
+ access_token
39
+ end
40
+
41
+ private
42
+
43
+ def get_token(app_id, app_secret)
44
+ http_get(token_url(app_id, app_secret))
45
+ end
46
+
47
+ def token_url(corpid, secret)
48
+ "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=#{corpid}&corpsecret=#{secret}"
49
+ end
50
+
51
+ def handle_res(res)
52
+ if res.code == '200'
53
+ return JSON.parse(res.body)
54
+ else
55
+ return {:code => res.code}.to_json
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ module YolSso
2
+ module Connection
3
+ module Message
4
+ def send_message(body)
5
+ http_post(send_url, body.merge("agentid": agentid))
6
+ end
7
+
8
+ private
9
+
10
+ def send_url
11
+ "#{host}messages"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ module YolSso
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 "yol_sso/helpers/pkcs7_encoder"
3
+ module YolSso
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
+ # raise BizErr, "#{__FILE__}:#{__LINE__} Failure because app_id != from_app_id"
22
+ status = 500
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
@@ -0,0 +1,11 @@
1
+ module YolSso
2
+ class Configuration
3
+
4
+ OPTIONS = [:host, :agentid].freeze
5
+
6
+ attr_accessor :host
7
+
8
+ attr_accessor :agentid
9
+
10
+ end
11
+ 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 YolSso
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
@@ -0,0 +1,3 @@
1
+ module YolSso
2
+ VERSION = "0.0.1"
3
+ end
data/pkg/.DS_Store ADDED
Binary file
data/yol_sso.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'yol_sso/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "yol_sso"
8
+ spec.version = YolSso::VERSION
9
+ spec.authors = ["luojie"]
10
+ spec.email = ["luojie@yolanda.hk"]
11
+ spec.summary = %q{Yolanda middleware for Message.}
12
+ spec.description = ""
13
+ spec.homepage = "https://github.com/luojie2019/yol_sso"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency 'nokogiri'
25
+ spec.add_dependency 'multi_xml'
26
+ spec.add_dependency 'roxml'
27
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yol_sso
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - luojie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_xml
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: roxml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: ''
84
+ email:
85
+ - luojie@yolanda.hk
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".DS_Store"
91
+ - Gemfile
92
+ - Gemfile.lock
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - lib/yol_sso.rb
97
+ - lib/yol_sso/client.rb
98
+ - lib/yol_sso/connection.rb
99
+ - lib/yol_sso/connections/base.rb
100
+ - lib/yol_sso/connections/message.rb
101
+ - lib/yol_sso/helpers/pkcs7_encoder.rb
102
+ - lib/yol_sso/helpers/prpcrypt.rb
103
+ - lib/yol_sso/models/configuration.rb
104
+ - lib/yol_sso/models/encrypt_message.rb
105
+ - lib/yol_sso/version.rb
106
+ - pkg/.DS_Store
107
+ - yol_sso.gemspec
108
+ homepage: https://github.com/luojie2019/yol_sso
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.7.9
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Yolanda middleware for Message.
132
+ test_files: []