bnet-authenticator 0.1.1 → 0.1.2
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/README.md +1 -1
- data/bnet-authenticator.gemspec +3 -2
- data/lib/bnet/authenticator.rb +21 -42
- data/lib/bnet/authenticator/core.rb +135 -136
- data/lib/bnet/authenticator/version.rb +1 -1
- data/test/test_battlenet_authenticator.rb +16 -12
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7056e70c2b6c9ef1287b439f7fdc4af94f7d12c
|
4
|
+
data.tar.gz: ea57bd0c4df97f40c4d5b28176388c5401f62f4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25eb9dbf2d68c0367ef0a9166c0e7633ba0cf7b51bfa5e972f0288ff1f694ed3badfc70a63153c487d64666fbad325297e54686bd6a23efd434f6cd3f42834c8
|
7
|
+
data.tar.gz: 9ba3f92663b958d3990dd161cf2d5563c3262d1a0c15831bd0ebc92b4fe2d08aa074be473efb44e907c1e557fc2f01b8f4fcd73ff34bd531cc89270ef67bbbdf
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Ruby implementation of the Battle.net Mobile Authenticator.
|
|
4
4
|
|
5
5
|
[](http://badge.fury.io/rb/bnet-authenticator)
|
6
6
|
|
7
|
-
[](https://travis-ci.org/dorentus/bnet-authenticator) [](https://gemnasium.com/dorentus/bnet-authenticator) [](https://coveralls.io/r/dorentus/bnet-authenticator)
|
7
|
+
[](https://travis-ci.org/dorentus/bnet-authenticator) [](https://gemnasium.com/dorentus/bnet-authenticator) [](https://coveralls.io/r/dorentus/bnet-authenticator) [](https://codeclimate.com/github/dorentus/bnet-authenticator)
|
8
8
|
|
9
9
|
Installation
|
10
10
|
====
|
data/bnet-authenticator.gemspec
CHANGED
@@ -17,8 +17,9 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.required_ruby_version = '>= 1.9.3'
|
18
18
|
|
19
19
|
if s.respond_to?(:add_development_dependency)
|
20
|
-
s.add_development_dependency 'rake', '~>
|
21
|
-
s.add_development_dependency '
|
20
|
+
s.add_development_dependency 'rake', '~> 10.1'
|
21
|
+
s.add_development_dependency 'minitest', '~> 5.0'
|
22
|
+
s.add_development_dependency 'yard', '~> 0.8'
|
22
23
|
s.add_development_dependency 'coveralls', '~> 0.7'
|
23
24
|
end
|
24
25
|
|
data/lib/bnet/authenticator.rb
CHANGED
@@ -2,7 +2,7 @@ require 'bnet/authenticator/core'
|
|
2
2
|
|
3
3
|
module Bnet
|
4
4
|
|
5
|
-
# The
|
5
|
+
# The battle.net authenticator
|
6
6
|
class Authenticator
|
7
7
|
|
8
8
|
# @!attribute [r] serial
|
@@ -13,7 +13,7 @@ module Bnet
|
|
13
13
|
# @return [String] hexified secret of the authenticator
|
14
14
|
attr_reader :secret
|
15
15
|
|
16
|
-
# @!attribute [r]
|
16
|
+
# @!attribute [r] restorecode
|
17
17
|
# @return [String] the restoration code of the authenticator
|
18
18
|
attr_reader :restorecode
|
19
19
|
|
@@ -21,37 +21,28 @@ module Bnet
|
|
21
21
|
# @return [Symbol] the region of the authenticator
|
22
22
|
attr_reader :region
|
23
23
|
|
24
|
-
#
|
24
|
+
# Create a new authenticator object
|
25
|
+
# @param options [Hash] read the examples for more infomation
|
25
26
|
#
|
26
|
-
# ==
|
27
|
+
# == Examples:
|
28
|
+
# >> # Create an authenticator object with given serial and secret
|
27
29
|
# >> Bnet::Authenticator.new(:serial => 'CN-1402-1943-1283', :secret => '4202aa2182640745d8a807e0fe7e34b30c1edb23')
|
28
30
|
# => Serial: CN-1402-1943-1283
|
29
31
|
# Secret: 4202aa2182640745d8a807e0fe7e34b30c1edb23
|
30
32
|
# Restoration Code: 4CKBN08QEB
|
31
33
|
#
|
34
|
+
# >> # Request server for a new authenticator
|
32
35
|
# >> Bnet::Authenticator.new(:region => :US)
|
33
36
|
# => Serial: US-1402-2552-9200
|
34
37
|
# Secret: c1307afe865735653d981771dff04ceb79b1a353
|
35
38
|
# Restoration Code: EQXCPB2YVE
|
36
39
|
#
|
40
|
+
# >> # Reqeust to restore an authenticator
|
37
41
|
# >> Bnet::Authenticator.new(:serial => 'CN-1402-1943-1283', :restorecode => '4CKBN08QEB')
|
38
42
|
# => Serial: CN-1402-1943-1283
|
39
43
|
# Secret: 4202aa2182640745d8a807e0fe7e34b30c1edb23
|
40
44
|
# Restoration Code: 4CKBN08QEB
|
41
45
|
#
|
42
|
-
# == Parameters:
|
43
|
-
# options:
|
44
|
-
# A Hash. Valid key combanations are:
|
45
|
-
#
|
46
|
-
# - :serial and :secret
|
47
|
-
# Create a new authenticator with given serial and secret.
|
48
|
-
#
|
49
|
-
# - :region
|
50
|
-
# Request for a new authenticator using given region.
|
51
|
-
#
|
52
|
-
# - :serial and :restorecode
|
53
|
-
# Reqeust to restore an authenticator using given serial and restoration code.
|
54
|
-
#
|
55
46
|
def initialize(options = {})
|
56
47
|
options = Core.normalize_options(options)
|
57
48
|
|
@@ -71,7 +62,7 @@ module Bnet
|
|
71
62
|
def restorecode
|
72
63
|
return nil if @serial.nil? or @secret.nil?
|
73
64
|
|
74
|
-
code_bin = Digest::SHA1.digest(
|
65
|
+
code_bin = Digest::SHA1.digest(Core.normalize_serial(@serial) + @secret.as_hex_to_bin).reverse[0, 10].reverse
|
75
66
|
Core.encode_restorecode(code_bin)
|
76
67
|
end
|
77
68
|
|
@@ -81,8 +72,8 @@ module Bnet
|
|
81
72
|
Core.extract_region(@serial)
|
82
73
|
end
|
83
74
|
|
84
|
-
# Caculate token using this authenticator's
|
85
|
-
# (defaults to current
|
75
|
+
# Caculate token using this authenticator's secret and given timestamp
|
76
|
+
# (in seconds, defaults to current timestamp)
|
86
77
|
#
|
87
78
|
# @param timestamp [Integer] a UNIX timestamp in seconds
|
88
79
|
# @return [String] current token
|
@@ -90,8 +81,14 @@ module Bnet
|
|
90
81
|
Core.caculate_token(@secret, timestamp)
|
91
82
|
end
|
92
83
|
|
93
|
-
#
|
94
|
-
#
|
84
|
+
# String representation of this authenticator
|
85
|
+
# @return [String]
|
86
|
+
def to_s
|
87
|
+
"Serial: #{serial}\nSecret: #{secret}\nRestoration Code: #{restorecode}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Caculate token using given secret and timestamp
|
91
|
+
# (in seconds, defaults to current timestamp)
|
95
92
|
#
|
96
93
|
# @param secret [String] hexified secret string of an authenticator
|
97
94
|
# @param timestamp [Integer] a UNIX timestamp in seconds
|
@@ -100,32 +97,14 @@ module Bnet
|
|
100
97
|
Core.caculate_token(secret, timestamp)
|
101
98
|
end
|
102
99
|
|
103
|
-
#
|
100
|
+
# Get server's time
|
104
101
|
#
|
105
102
|
# @param region [Symbol]
|
106
|
-
# @return [Integer] server timestamp
|
103
|
+
# @return [Integer] server timestamp in seconds
|
107
104
|
def self.request_server_time(region)
|
108
105
|
Core.request_server_time(region)
|
109
106
|
end
|
110
107
|
|
111
|
-
# String representation of this authenticator
|
112
|
-
# @return [String]
|
113
|
-
def to_s
|
114
|
-
"Serial: #{serial}\nSecret: #{secret}\nRestoration Code: #{restorecode}"
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def normalized_serial
|
120
|
-
Core.normalize_serial(@serial)
|
121
|
-
end
|
122
|
-
|
123
|
-
def binary_secret
|
124
|
-
return nil if @secret.nil?
|
125
|
-
|
126
|
-
@secret.as_hex_to_bin
|
127
|
-
end
|
128
|
-
|
129
108
|
end
|
130
109
|
|
131
110
|
end
|
@@ -13,9 +13,9 @@ module Bnet
|
|
13
13
|
RSA_MOD = 104890018807986556874007710914205443157030159668034197186125678960287470894290830530618284943118405110896322835449099433232093151168250152146023319326491587651685252774820340995950744075665455681760652136576493028733914892166700899109836291180881063097461175643998356321993663868233366705340758102567742483097
|
14
14
|
RSA_KEY = 257
|
15
15
|
AUTHENTICATOR_HOSTS = {
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
:CN => "mobile-service.battlenet.com.cn",
|
17
|
+
:EU => "m.eu.mobileservice.blizzard.com",
|
18
|
+
:US => "m.us.mobileservice.blizzard.com",
|
19
19
|
}
|
20
20
|
ENROLLMENT_REQUEST_PATH = '/enrollment/enroll.htm'
|
21
21
|
TIME_REQUEST_PATH = '/enrollment/time.htm'
|
@@ -37,135 +37,57 @@ module Bnet
|
|
37
37
|
end
|
38
38
|
RESTORECODE_MAP_INVERSE = RESTORECODE_MAP.invert
|
39
39
|
|
40
|
-
def self.caculate_token(secret, timestamp = nil)
|
41
|
-
secret = normalize_options(:secret => secret)[:secret]
|
42
|
-
return nil if secret.nil?
|
43
|
-
|
44
|
-
timestamp = Time.now.getutc.to_i if timestamp.nil?
|
45
|
-
|
46
|
-
current = timestamp / 30
|
47
|
-
next_timestamp = (current + 1) * 30
|
48
|
-
|
49
|
-
digest = Digest::HMAC.digest([current].pack('Q>'), secret.as_hex_to_bin, Digest::SHA1)
|
50
|
-
|
51
|
-
start_position = digest[19].ord & 0xf
|
52
|
-
|
53
|
-
token = '%08d' % (digest[start_position, 4].as_bin_to_i % 100000000)
|
54
|
-
|
55
|
-
return token, next_timestamp
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.normalize_serial(serial)
|
59
|
-
serial.to_s.gsub(/-/, '').upcase
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.prettify_serial(serial)
|
63
|
-
serial = normalize_serial(serial)
|
64
|
-
"#{serial[0, 2]}-" + serial[2, 12].scan(/.{4}/).join('-')
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
40
|
def self.normalize_options(options)
|
70
41
|
return nil if options.nil?
|
71
42
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
options[:serial] = prettify_serial(normalized_serial)
|
78
|
-
else
|
79
|
-
raise BadInputError.new("bad serial #{options[:serial]}")
|
43
|
+
%w(serial region restorecode secret).each do |attr|
|
44
|
+
if options.has_key? attr.to_sym
|
45
|
+
options[attr.to_sym] = send "normalize_#{attr}".to_sym, options[attr.to_sym] do |value|
|
46
|
+
raise BadInputError.new("bad #{attr} #{value}")
|
47
|
+
end
|
80
48
|
end
|
81
49
|
end
|
82
50
|
|
83
|
-
if options.has_key?(:
|
84
|
-
region = options[:region].to_s.upcase.to_sym
|
85
|
-
raise BadInputError.new("unsupported region #{region}") unless AUTHENTICATOR_HOSTS.has_key?(region)
|
86
|
-
|
87
|
-
options[:region] = region
|
88
|
-
end
|
89
|
-
|
90
|
-
if options.has_key?(:restorecode)
|
91
|
-
restorecode = options[:restorecode].upcase
|
92
|
-
|
93
|
-
raise BadInputError.new("bad restoration code #{restorecode}") unless restorecode =~ /[0-9A-Z]{10}/
|
94
|
-
|
95
|
-
options[:restorecode] = restorecode
|
96
|
-
end
|
97
|
-
|
98
|
-
if options.has_key?(:secret)
|
99
|
-
secret = options[:secret]
|
100
|
-
raise BadInputError.new("bad secret #{secret}") unless secret =~ /[0-9a-f]{40}/i
|
101
|
-
end
|
51
|
+
options[:serial] = prettify_serial(options[:serial]) if options.has_key?(:serial)
|
102
52
|
|
103
53
|
options
|
104
54
|
end
|
105
55
|
|
106
|
-
def self.extract_region(serial)
|
107
|
-
serial.to_s[0, 2].upcase.to_sym
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.create_one_time_pad(length)
|
111
|
-
(0..1.0/0.0).reduce('') do |memo, i|
|
112
|
-
break memo if memo.length >= length
|
113
|
-
memo << Digest::SHA1.digest(rand().to_s)
|
114
|
-
end[0, length]
|
115
|
-
end
|
116
|
-
|
117
56
|
def self.encode_restorecode(bin)
|
118
57
|
bin.bytes.map do |v|
|
119
58
|
RESTORECODE_MAP[v & 0x1f]
|
120
59
|
end.as_bytes_to_bin
|
121
60
|
end
|
122
61
|
|
123
|
-
def self.
|
124
|
-
|
125
|
-
RESTORECODE_MAP_INVERSE[c]
|
126
|
-
end.as_bytes_to_bin
|
62
|
+
def self.extract_region(serial)
|
63
|
+
serial.to_s[0, 2].upcase.to_sym
|
127
64
|
end
|
128
65
|
|
129
|
-
def self.
|
130
|
-
|
66
|
+
def self.caculate_token(secret, timestamp = nil)
|
67
|
+
secret = normalize_secret secret do |invalid_secret|
|
68
|
+
return nil
|
69
|
+
end
|
131
70
|
|
132
|
-
|
133
|
-
k = create_one_time_pad(37)
|
71
|
+
current = (timestamp || Time.now.getutc.to_i) / 30
|
134
72
|
|
135
|
-
|
136
|
-
# 00 byte[1] 固定为1
|
137
|
-
# 01 byte[37] 37位的随机数据,只使用一次,用来解密服务器返回数据
|
138
|
-
# 38 byte[2] 区域码: CN, US, EU, etc.
|
139
|
-
# 40 byte[16] 设备模型数据(手机型号字符串,可随意)
|
140
|
-
bytes = [1]
|
141
|
-
bytes.concat(k.bytes.to_a)
|
142
|
-
bytes.concat(region.to_s.bytes.take(2))
|
143
|
-
bytes.concat(model.ljust(16, "\0").bytes.take(16))
|
73
|
+
digest = Digest::HMAC.digest([current].pack('Q>'), secret.as_hex_to_bin, Digest::SHA1)
|
144
74
|
|
145
|
-
|
146
|
-
e = (bytes.as_bytes_to_i ** RSA_KEY % RSA_MOD).to_bin
|
75
|
+
start_position = digest[19].ord & 0xf
|
147
76
|
|
148
|
-
|
149
|
-
request = Net::HTTP::Post.new(ENROLLMENT_REQUEST_PATH)
|
150
|
-
request.content_type = 'application/octet-stream'
|
151
|
-
request.body = e
|
77
|
+
token = '%08d' % (digest[start_position, 4].as_bin_to_i % 100000000)
|
152
78
|
|
153
|
-
|
154
|
-
|
155
|
-
end
|
79
|
+
return token, (current + 1) * 30
|
80
|
+
end
|
156
81
|
|
157
|
-
|
158
|
-
|
159
|
-
# [206, 166, 17, 196, 68, 160, 142, 111, 216, 196, 170, 19, 49, 239, 101, 93, 114, 241, 57, 223, 150, 80, 219, 114, 95, 20, 42, 142, 193, 115, 79, 71, 189, 147, 242, 111, 27].as_bytes_to_bin
|
160
|
-
raise RequestFailedError.new("Error requesting for new serial: #{response.code}") if response.code.to_i(10) != 200
|
82
|
+
def self.request_new_serial(region, model = nil)
|
83
|
+
e, k = prepair_serial_request(region, model || 'bn/authenticator')
|
161
84
|
|
162
|
-
#
|
163
|
-
|
85
|
+
# request to server
|
86
|
+
response_body = request_for('new serial', region, ENROLLMENT_REQUEST_PATH, e)
|
164
87
|
|
88
|
+
# the first 8 bytes be server timestamp in milliseconds
|
165
89
|
# the rest 37 bytes, to be XORed with `k`
|
166
|
-
decrypted =
|
167
|
-
memo << (pair[0] ^ pair[1]).chr
|
168
|
-
end
|
90
|
+
decrypted = decrypt_response(response_body[8, 37], k)
|
169
91
|
|
170
92
|
# now
|
171
93
|
# the first 20 bytes be the authenticator secret
|
@@ -182,56 +104,133 @@ module Bnet
|
|
182
104
|
restorecode_bin = decode_restorecode(restorecode)
|
183
105
|
|
184
106
|
# stage 1
|
185
|
-
|
186
|
-
request.content_type = 'application/octet-stream'
|
187
|
-
request.body = serial_normalized
|
188
|
-
|
189
|
-
response = Net::HTTP.new(AUTHENTICATOR_HOSTS[region]).start do |http|
|
190
|
-
http.request(request)
|
191
|
-
end
|
192
|
-
|
193
|
-
raise RequestFailedError.new("Error requesting for restore (stage 1): #{response.code}") if response.code.to_i(10) != 200
|
107
|
+
challenge = request_for('restore (stage 1)', region, RESTORE_INIT_REQUEST_PATH, serial_normalized)
|
194
108
|
|
195
109
|
# stage 2
|
196
|
-
challenge = response.body
|
197
|
-
|
198
110
|
key = create_one_time_pad(20)
|
199
111
|
|
200
112
|
digest = Digest::HMAC.digest(serial_normalized + challenge,
|
201
113
|
restorecode_bin,
|
202
114
|
Digest::SHA1)
|
203
115
|
|
204
|
-
payload = serial_normalized
|
205
|
-
payload += ((digest+key).as_bin_to_i ** RSA_KEY % RSA_MOD).to_bin
|
206
|
-
|
207
|
-
request = Net::HTTP::Post.new(RESTORE_VALIDATE_REQUEST_PATH)
|
208
|
-
request.content_type = 'application/octet-stream'
|
209
|
-
request.body = payload
|
210
|
-
|
211
|
-
response = Net::HTTP.new(AUTHENTICATOR_HOSTS[region]).start do |http|
|
212
|
-
http.request(request)
|
213
|
-
end
|
116
|
+
payload = serial_normalized + rsa_encrypted((digest + key).as_bin_to_i)
|
214
117
|
|
215
|
-
|
118
|
+
response_body = request_for('restore (stage 2)', region, RESTORE_VALIDATE_REQUEST_PATH, payload)
|
216
119
|
|
217
|
-
secret =
|
218
|
-
memo << (pair[0] ^ pair[1]).chr
|
219
|
-
end.as_bin_to_hex
|
120
|
+
secret = decrypt_response(response_body, key).as_bin_to_hex
|
220
121
|
|
221
122
|
return prettify_serial(serial), secret
|
222
123
|
end
|
223
124
|
|
224
125
|
def self.request_server_time(region)
|
225
|
-
|
226
|
-
|
126
|
+
request_for('server time', region, TIME_REQUEST_PATH).as_bin_to_i.to_f / 1000
|
127
|
+
end
|
128
|
+
|
129
|
+
class << self
|
130
|
+
|
131
|
+
def normalize_serial(serial)
|
132
|
+
s = serial.to_s.gsub(/-/, '').upcase
|
133
|
+
|
134
|
+
if block_given?
|
135
|
+
region = extract_region(s)
|
136
|
+
yield serial unless (AUTHENTICATOR_HOSTS.has_key?(region) && s =~ /\d{12}/)
|
137
|
+
end
|
138
|
+
|
139
|
+
s
|
140
|
+
end
|
141
|
+
|
142
|
+
def prettify_serial(serial)
|
143
|
+
serial = normalize_serial(serial) { |bad_serial| return nil }
|
144
|
+
"#{serial[0, 2]}-" + serial[2, 12].scan(/.{4}/).join('-')
|
145
|
+
end
|
146
|
+
|
147
|
+
def normalize_region(region)
|
148
|
+
normalized_region = region.to_s.upcase.to_sym
|
149
|
+
|
150
|
+
if block_given? && !AUTHENTICATOR_HOSTS.has_key?(normalized_region)
|
151
|
+
yield region
|
152
|
+
end
|
153
|
+
|
154
|
+
normalized_region
|
155
|
+
end
|
156
|
+
|
157
|
+
def normalize_restorecode(restorecode)
|
158
|
+
restorecode = restorecode.upcase
|
159
|
+
|
160
|
+
if block_given? && !(restorecode =~ /[0-9A-Z]{10}/)
|
161
|
+
yield restorecode
|
162
|
+
end
|
227
163
|
|
228
|
-
|
229
|
-
http.request(request)
|
164
|
+
restorecode
|
230
165
|
end
|
231
166
|
|
232
|
-
|
167
|
+
def normalize_secret(secret)
|
168
|
+
if block_given? && !(secret =~ /[0-9a-f]{40}/i)
|
169
|
+
yield secret
|
170
|
+
end
|
171
|
+
|
172
|
+
secret
|
173
|
+
end
|
174
|
+
|
175
|
+
def create_one_time_pad(length)
|
176
|
+
(0..1.0/0.0).reduce('') do |memo, i|
|
177
|
+
break memo if memo.length >= length
|
178
|
+
memo << Digest::SHA1.digest(rand().to_s)
|
179
|
+
end[0, length]
|
180
|
+
end
|
181
|
+
|
182
|
+
def decode_restorecode(str)
|
183
|
+
str.bytes.map do |c|
|
184
|
+
RESTORECODE_MAP_INVERSE[c]
|
185
|
+
end.as_bytes_to_bin
|
186
|
+
end
|
187
|
+
|
188
|
+
def decrypt_response(text, key)
|
189
|
+
text.bytes.zip(key.bytes).reduce('') do |memo, pair|
|
190
|
+
memo + (pair[0] ^ pair[1]).chr
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def rsa_encrypted(integer)
|
195
|
+
(integer ** RSA_KEY % RSA_MOD).to_bin
|
196
|
+
end
|
197
|
+
|
198
|
+
def prepair_serial_request(region, model)
|
199
|
+
# one-time key of 37 bytes
|
200
|
+
k = create_one_time_pad(37)
|
201
|
+
|
202
|
+
# make byte[56]
|
203
|
+
# 00 byte[1] 固定为1
|
204
|
+
# 01 byte[37] 37位的随机数据,只使用一次,用来解密服务器返回数据
|
205
|
+
# 38 byte[2] 区域码: CN, US, EU, etc.
|
206
|
+
# 40 byte[16] 设备模型数据(手机型号字符串,可随意)
|
207
|
+
bytes = [1]
|
208
|
+
bytes.concat(k.bytes.to_a)
|
209
|
+
bytes.concat(region.to_s.bytes.take(2))
|
210
|
+
bytes.concat(model.ljust(16, "\0").bytes.take(16))
|
211
|
+
|
212
|
+
# encrypted using RSA
|
213
|
+
e = rsa_encrypted(bytes.as_bytes_to_i)
|
214
|
+
|
215
|
+
return e, k
|
216
|
+
end
|
217
|
+
|
218
|
+
def request_for(label, region, path, body = nil)
|
219
|
+
request = body.nil? ? Net::HTTP::Get.new(path) : Net::HTTP::Post.new(path)
|
220
|
+
request.content_type = 'application/octet-stream'
|
221
|
+
request.body = body unless body.nil?
|
222
|
+
|
223
|
+
response = Net::HTTP.new(AUTHENTICATOR_HOSTS[region]).start do |http|
|
224
|
+
http.request request
|
225
|
+
end
|
226
|
+
|
227
|
+
if response.code.to_i != 200
|
228
|
+
raise RequestFailedError.new("Error requesting #{label}: #{response.code}")
|
229
|
+
end
|
230
|
+
|
231
|
+
response.body
|
232
|
+
end
|
233
233
|
|
234
|
-
response.body.as_bin_to_i.to_f / 1000.0
|
235
234
|
end
|
236
235
|
|
237
236
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'coveralls'
|
2
2
|
Coveralls.wear_merged!
|
3
3
|
|
4
|
-
|
4
|
+
gem "minitest"
|
5
|
+
require 'minitest/autorun'
|
5
6
|
require 'bnet/authenticator'
|
6
7
|
|
7
|
-
class Bnet::AuthenticatorTest < Test
|
8
|
+
class Bnet::AuthenticatorTest < Minitest::Test
|
8
9
|
DEFAULT_SERIAL = 'CN-1402-1943-1283'
|
9
10
|
DEFAULT_SECRET = '4202aa2182640745d8a807e0fe7e34b30c1edb23'
|
10
11
|
DEFAULT_RSCODE = '4CKBN08QEB'
|
@@ -16,19 +17,19 @@ class Bnet::AuthenticatorTest < Test::Unit::TestCase
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def test_argument_error
|
19
|
-
|
20
|
+
assert_raises ::Bnet::Authenticator::BadInputError do
|
20
21
|
Bnet::Authenticator.new
|
21
22
|
end
|
22
23
|
|
23
|
-
|
24
|
+
assert_raises ::Bnet::Authenticator::BadInputError do
|
24
25
|
Bnet::Authenticator.new(:serial => 'ABC')
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
assert_raises ::Bnet::Authenticator::BadInputError do
|
28
29
|
Bnet::Authenticator.new(:region => 'SG')
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
+
assert_raises ::Bnet::Authenticator::BadInputError do
|
32
33
|
Bnet::Authenticator.new(:restorecode => 'DDDD')
|
33
34
|
end
|
34
35
|
end
|
@@ -37,10 +38,11 @@ class Bnet::AuthenticatorTest < Test::Unit::TestCase
|
|
37
38
|
begin
|
38
39
|
authenticator = Bnet::Authenticator.new(:region => :US)
|
39
40
|
assert_equal :US, authenticator.region
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
rescue Bnet::Authenticator::RequestFailedError
|
41
|
+
refute_nil authenticator.serial
|
42
|
+
refute_nil authenticator.secret
|
43
|
+
refute_nil authenticator.restorecode
|
44
|
+
rescue Bnet::Authenticator::RequestFailedError => e
|
45
|
+
puts e
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
@@ -48,14 +50,16 @@ class Bnet::AuthenticatorTest < Test::Unit::TestCase
|
|
48
50
|
begin
|
49
51
|
authenticator = Bnet::Authenticator.new(:serial => DEFAULT_SERIAL, :restorecode => DEFAULT_RSCODE)
|
50
52
|
is_default_authenticator authenticator
|
51
|
-
rescue Bnet::Authenticator::RequestFailedError
|
53
|
+
rescue Bnet::Authenticator::RequestFailedError => e
|
54
|
+
puts e
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
55
58
|
def test_request_server_time
|
56
59
|
begin
|
57
60
|
Bnet::Authenticator.request_server_time :EU
|
58
|
-
rescue Bnet::Authenticator::RequestFailedError
|
61
|
+
rescue Bnet::Authenticator::RequestFailedError => e
|
62
|
+
puts e
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bnet-authenticator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ZHANG Yi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -16,28 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '10.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '10.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: yard
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
47
|
+
version: '0.8'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
54
|
+
version: '0.8'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: coveralls
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|