Commit 07d8eeec by Francis Zhou

add robot message builder

parent e89d6223
......@@ -25,8 +25,14 @@ module DingtalkSdk
end
class Signature
def initialize(signature)
def initialize(signature, url_encoded = false)
if url_encoded
@signature = URI.decode_www_form_component signature
@encoded_signature = signature
else
@signature = signature
@encoded_signature = URI.encode_www_form_component signature
end
end
def to_s
......@@ -34,7 +40,7 @@ module DingtalkSdk
end
def url_encoded
URI.encode_www_form_component @signature
@encoded_signature
end
end
......
......@@ -21,22 +21,23 @@ module DingtalkSdk
# 通过 Request.set_access_token_cache_method 定义缓存方法
# @return [Hash]
def cached_access_token
method_name = :@@ak_cache_method
var_name = :@ak_cache_method
return get_access_token unless self.class.class_variable_defined? method_name
return get_access_token unless self.class.instance_variable_defined?(var_name)
self.class.class_variable_get(method_name).call(self)
self.class.instance_variable_get(var_name).call(self)
end
module ClassMethods
def set_access_token_cache_method
raise ArgumentError, 'invalid access_token cache method' unless block_given?
class_variable_set :@@ak_cache_method, ->(request) { yield request }
@ak_cache_method = ->(request) { yield request }
end
def unset_access_token_cache_method
remove_class_variable :@@ak_cache_method if class_variable_defined?(@@ak_cache_method)
var_name = :@ak_cache_method
remove_instance_variable(var_name) if instance_variable_defined?(var_name)
end
end
......
......@@ -8,13 +8,16 @@ require 'dingtalk_sdk/core'
require 'dingtalk_sdk/request_url'
require 'active_support/core_ext/object'
require 'active_support/core_ext/integer'
require 'active_support/core_ext/time/zones'
module DingtalkSdk
module Robot
extend DingtalkSdk::Core
def self.calculate_signature(secret, timestamp)
class << self
# 计算签名
# timestamp 为毫秒单位
# @return [DingtalkSdk::Signature]
def calculate_signature(secret, timestamp)
raise ArgumentError, 'timestamp must in millis' if Math.log10(timestamp).ceil < 13
origin_str = [timestamp, secret].join("\n")
......@@ -24,10 +27,30 @@ module DingtalkSdk
Signature.new(signature_str_base64)
end
def self.verify_signature(secret, signature, timestamp = Time.zone.now)
return false if Time.zone.now - timestamp > 1.hour
# 验证一个签名是否有效
# @option timestamp 时间戳
# @option url_encoded 签名是否经过 url encode
# @option verify_timestamp 验证签名是否在有效时间段内 (1小时)
# @return [Boolean]
def verify_signature(secret, expected_signature, options = {})
options.with_defaults!(
timestamp: Time.now.to_i * 1000,
url_encoded: false,
verify_timestamp: true
)
calculate_signature(secret, timestamp.to_i * 1000) == signature
if options[:verify_signature]
datetime_timestamp = Time.at(options[:timestamp] / 1000)
return false if Time.now - datetime_timestamp > 1.hour
end
actually_signature = calculate_signature(secret, options[:timestamp])
expected_signature == if options[:url_encoded]
actually_signature.url_encoded
else
actually_signature.to_s
end
end
end
class MessageBuilder
......@@ -96,7 +119,7 @@ module DingtalkSdk
def at_mobile(mobile)
@is_at_all = false
@at_mobile_list = [*mobile]
@at_mobile_list = [*mobile].map(&:to_s).uniq
end
def at_all
......@@ -110,7 +133,7 @@ module DingtalkSdk
if @is_at_all
h[:isAtAll] = true
elsif @at_mobile_list.try(:size).positive?
elsif @at_mobile_list.try(:size).try(:positive?)
h[:atMobiles] = @at_mobile_list
end
end
......
......@@ -11,4 +11,45 @@ RSpec.describe DingtalkSdk::Robot do
expect(sign.url_encoded).to eq('3E1RZgQrn1ZLgQGU4C4n4SMei%2BObeZVym5BbqrwOJPs%3D')
end
it 'should return true in verify_signature' do
timestamp = 1_603_868_410_000
secret = 'this is secret'
signature = '3E1RZgQrn1ZLgQGU4C4n4SMei+ObeZVym5BbqrwOJPs='
is_valid = DingtalkSdk::Robot.verify_signature(
secret,
signature,
{
timestamp: timestamp,
url_encoded: false,
verify_timestamp: false
}
)
expect(is_valid).to be_truthy
end
describe DingtalkSdk::Robot::MessageBuilder do
it 'should compose text message' do
builder = DingtalkSdk::Robot::MessageBuilder.new
builder.text text: 'hello world'
mesg_h = builder.to_h
expect(mesg_h[:msgtype]).to eq('text')
expect(mesg_h[:text][:content]).to eq('hello world')
expect(mesg_h[:isAtAll]).to be_nil
expect(mesg_h[:atMobiles]).to be_nil
end
it 'should compose message with at mobiles' do
builder = DingtalkSdk::Robot::MessageBuilder.new
builder.text text: 'hello world'
builder.at_mobile [123, 456]
mesg_h = builder.to_h
expect(mesg_h[:isAtAll]).to be_nil
expect(mesg_h[:atMobiles]).to eq(%w[123 456])
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment