rfetion 0.5.6 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/lib/rfetion/buddy_list.rb +2 -2
- data/lib/rfetion/contact.rb +5 -4
- data/lib/rfetion/fetion.rb +23 -15
- data/lib/rfetion/pic_certificate.rb +10 -5
- data/lib/rfetion/sipc_message.rb +1 -1
- data/rfetion.gemspec +11 -5
- data/spec/rfetion/buddy_list_spec.rb +10 -1
- data/spec/rfetion/fetion_spec.rb +4 -2
- data/spec/rfetion/sipc_message_spec.rb +1 -0
- metadata +28 -6
data/Rakefile
CHANGED
@@ -29,8 +29,10 @@ Jeweler::Tasks.new do |gemspec|
|
|
29
29
|
gemspec.homepage = 'http://github.com/flyerhzm/rfetion'
|
30
30
|
gemspec.authors = ['Richard Huang']
|
31
31
|
gemspec.files.exclude '.gitignore'
|
32
|
-
gemspec.add_dependency 'guid'
|
32
|
+
gemspec.add_dependency 'guid'
|
33
33
|
gemspec.add_dependency 'nokogiri'
|
34
|
+
gemspec.add_dependency 'json'
|
35
|
+
gemspec.add_dependency 'macaddr'
|
34
36
|
gemspec.executables << 'rfetion'
|
35
37
|
end
|
36
38
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.7
|
data/lib/rfetion/buddy_list.rb
CHANGED
@@ -8,8 +8,8 @@ class Fetion
|
|
8
8
|
@contacts = []
|
9
9
|
end
|
10
10
|
|
11
|
-
def to_json
|
12
|
-
{:bid => @bid, :name => @name, :contacts => @contacts}.to_json
|
11
|
+
def to_json(*args)
|
12
|
+
{:bid => @bid, :name => @name, :contacts => @contacts, :total_contacts => total_contacts_count, :online_contacts => online_contacts_count}.to_json(*args)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.parse(buddy_list)
|
data/lib/rfetion/contact.rb
CHANGED
@@ -10,8 +10,8 @@ class Fetion
|
|
10
10
|
"0" => "脱机"
|
11
11
|
}
|
12
12
|
|
13
|
-
def to_json
|
14
|
-
{:uid => @uid, :sid => @sid, :bid => @bid, :uri => @uri, :mobile_no => @mobile_no, :nickname => @nickname, :impresa => @impresa, :status => @status}.to_json
|
13
|
+
def to_json(*args)
|
14
|
+
{:uid => @uid, :sid => @sid, :bid => @bid, :uri => @uri, :mobile_no => @mobile_no, :nickname => @nickname, :impresa => @impresa, :status => @status, :display => display}.to_json(*args)
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.parse_buddy(b)
|
@@ -28,18 +28,19 @@ class Fetion
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def initialize(options={})
|
31
|
+
@status = "0"
|
31
32
|
options.each do |key, value|
|
32
33
|
send("#{key}=", value)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
|
-
def update(p)
|
37
|
+
def update(p, pr)
|
37
38
|
self.sid = p["sid"] if p["sid"] and !p["sid"].empty?
|
38
39
|
self.uri = p["su"] if p["su"] and !p["su"].empty?
|
39
40
|
self.mobile_no = p["m"] if p["m"] and !p["m"].empty?
|
40
41
|
self.nickname = p["n"] if p["n"] and !p["n"].empty?
|
41
42
|
self.impresa = p["i"] if p["i"] and !p["i"].empty?
|
42
|
-
self.status =
|
43
|
+
self.status = pr["b"] if pr["b"] and !pr["b"].empty?
|
43
44
|
end
|
44
45
|
|
45
46
|
def display
|
data/lib/rfetion/fetion.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
#coding: utf-8
|
1
2
|
require 'guid'
|
2
3
|
require 'time'
|
3
4
|
require 'net/http'
|
4
5
|
require 'net/https'
|
5
6
|
require 'nokogiri'
|
6
7
|
require 'digest/sha1'
|
8
|
+
require 'digest/md5'
|
9
|
+
require 'macaddr'
|
7
10
|
require 'openssl'
|
8
11
|
require 'logger'
|
9
12
|
require 'json'
|
10
13
|
|
11
14
|
class Fetion
|
12
|
-
attr_accessor :mobile_no, :sid, :password, :call, :seq, :alive, :ssic, :guid, :uri
|
15
|
+
attr_accessor :mobile_no, :sid, :password, :call, :seq, :alive, :ssic, :guid, :uri, :pid, :pic, :algorithm, :machine_code
|
13
16
|
attr_reader :uid, :buddy_lists, :add_requests, :response, :nickname, :impresa, :receives
|
14
17
|
|
15
18
|
FETION_URL = 'http://221.176.31.39/ht/sd.aspx'
|
@@ -32,8 +35,8 @@ class Fetion
|
|
32
35
|
@guid = Guid.new.to_s
|
33
36
|
end
|
34
37
|
|
35
|
-
def to_json
|
36
|
-
{:mobile_no => @mobile_no, :sid => @sid, :uid => @uid, :uri => @uri, :status_code => @status_code, :buddy_lists => @buddy_lists, :receives => @receives, :add_requests => @add_requests, :nickname => @nickname, :impresa => @impresa, :ssic => @ssic, :guid => @guid, :call => @call, :seq => @seq, :alive => @alive}.to_json
|
38
|
+
def to_json(*args)
|
39
|
+
{:mobile_no => @mobile_no, :sid => @sid, :uid => @uid, :uri => @uri, :status_code => @status_code, :buddy_lists => @buddy_lists, :receives => @receives, :add_requests => @add_requests, :nickname => @nickname, :impresa => @impresa, :ssic => @ssic, :guid => @guid, :call => @call, :seq => @seq, :alive => @alive}.to_json(*args)
|
37
40
|
end
|
38
41
|
|
39
42
|
def logger_level=(level)
|
@@ -169,7 +172,9 @@ class Fetion
|
|
169
172
|
else
|
170
173
|
url = FETION_LOGIN_URL.sub('%sid%', @sid).sub('mobileno=%mobileno%', '')
|
171
174
|
end
|
172
|
-
|
175
|
+
url.sub!('%digest%', Digest::SHA1.hexdigest("#{DOMAIN}:#{@password}"))
|
176
|
+
url += "&pid=#@pid&pic=#@pic&algorithm=#@algorithm" if @pic
|
177
|
+
uri = URI.parse(url)
|
173
178
|
http = Net::HTTP.new(uri.host, uri.port)
|
174
179
|
http.use_ssl = true
|
175
180
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
@@ -204,7 +209,6 @@ class Fetion
|
|
204
209
|
def register_second
|
205
210
|
@logger.debug "fetion register second"
|
206
211
|
|
207
|
-
body = %Q|<args><device machine-code="B04B5DA2F5F1B8D01A76C0EBC841414C" /><caps value="ff" /><events value="7f" /><user-info mobile-no="#{@mobile_no}" user-id="#{@uid}"><personal version="0" attributes="v4default" /><custom-config version="0" /><contact-list version="0" buddy-attributes="v4default" /></user-info><credentials domains="fetion.com.cn;m161.com.cn;www.ikuwa.cn;games.fetion.com.cn" /><presence><basic value="400" desc="" /></presence></args>|
|
208
212
|
curl_exec(SipcMessage.register_second(self))
|
209
213
|
pulse
|
210
214
|
|
@@ -369,17 +373,17 @@ class Fetion
|
|
369
373
|
http = Net::HTTP.new(uri.host, uri.port)
|
370
374
|
headers = {'User-Agent' => USER_AGENT}
|
371
375
|
response = http.request_get(uri.request_uri, headers)
|
372
|
-
pic_certificate = parse_pic_certificate(response)
|
376
|
+
pic_certificate = parse_pic_certificate(response, algorithm)
|
373
377
|
|
374
378
|
@logger.info "fetion get pic success"
|
375
379
|
pic_certificate
|
376
380
|
end
|
377
381
|
|
378
382
|
def parse_ssic(response)
|
379
|
-
raise Fetion::PasswordError.new('
|
380
|
-
raise Fetion::PasswordMaxError.new('
|
381
|
-
raise Fetion::LoginException.new('
|
382
|
-
raise Fetion::LoginException.new('
|
383
|
+
raise Fetion::PasswordError.new('帐号或密码不正确') if Net::HTTPUnauthorized === response
|
384
|
+
raise Fetion::PasswordMaxError.new('您已连续输入错误密码,为了保障您的帐户安全,请输入图形验证码:') if Net::HTTPClientError === response
|
385
|
+
raise Fetion::LoginException.new('Login failed.') unless Net::HTTPSuccess === response
|
386
|
+
raise Fetion::LoginException.new('No ssic found in cookie.') unless response['set-cookie'] =~ /ssic=(.*);/
|
383
387
|
|
384
388
|
@ssic = $1
|
385
389
|
@logger.debug response.body
|
@@ -404,11 +408,11 @@ class Fetion
|
|
404
408
|
@logger.debug "sid: " + @sid
|
405
409
|
end
|
406
410
|
|
407
|
-
def parse_pic_certificate(response)
|
408
|
-
raise FetionException.new('
|
411
|
+
def parse_pic_certificate(response, algorithm)
|
412
|
+
raise FetionException.new('Get verification code failed.') unless Net::HTTPSuccess === response
|
409
413
|
doc = Nokogiri::XML(response.body)
|
410
414
|
certificate = doc.root.xpath('/results/pic-certificate').first
|
411
|
-
PicCertificate.parse(certificate)
|
415
|
+
PicCertificate.parse(certificate, algorithm)
|
412
416
|
end
|
413
417
|
|
414
418
|
def curl_exec(body='', url=next_url, expected=SipcMessage::OK)
|
@@ -433,7 +437,7 @@ class Fetion
|
|
433
437
|
|
434
438
|
if sipc_response.first_line =~ /401/
|
435
439
|
# unauthorized, get nonce, key and signature
|
436
|
-
raise Fetion::NoNonceException.new("
|
440
|
+
raise Fetion::NoNonceException.new("No nonce found") unless response.body =~ /nonce="(.*?)",key="(.*?)",signature="(.*?)"/
|
437
441
|
@nonce = $1
|
438
442
|
@key = $2
|
439
443
|
@signature = $3
|
@@ -485,7 +489,7 @@ class Fetion
|
|
485
489
|
unless self.uid == c['id']
|
486
490
|
contact = contacts.find {|contact| contact.uid == c['id']}
|
487
491
|
if contact
|
488
|
-
contact.update(c.children.first)
|
492
|
+
contact.update(c.children.first, c.children.last)
|
489
493
|
else
|
490
494
|
contact = Fetion::Contact.parse(c)
|
491
495
|
if @buddy_lists.size > 1
|
@@ -532,6 +536,10 @@ class Fetion
|
|
532
536
|
|
533
537
|
rsa_key.public_encrypt(str).unpack("H*").first.upcase
|
534
538
|
end
|
539
|
+
|
540
|
+
def machine_code
|
541
|
+
@machine_code ||= Digest::MD5.hexdigest(Mac.addr)
|
542
|
+
end
|
535
543
|
|
536
544
|
def self?(mobile_or_sid)
|
537
545
|
mobile_or_sid == @mobile_no or mobile_or_sid == @sid
|
@@ -1,12 +1,17 @@
|
|
1
1
|
class PicCertificate
|
2
|
-
attr_reader :
|
2
|
+
attr_reader :pid, :pic, :algorithm
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(pid, pic, algorithm)
|
5
|
+
@pid = pid
|
6
6
|
@pic = pic
|
7
|
+
@algorithm = algorithm
|
7
8
|
end
|
8
9
|
|
9
|
-
def self.parse(c)
|
10
|
-
PicCertificate.new(c['id'], c['pic'])
|
10
|
+
def self.parse(c, algorithm)
|
11
|
+
PicCertificate.new(c['id'], c['pic'], algorithm)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json(*args)
|
15
|
+
{:pid => @pid, :pic => @pic, :algorithm => @algorithm}
|
11
16
|
end
|
12
17
|
end
|
data/lib/rfetion/sipc_message.rb
CHANGED
@@ -6,7 +6,7 @@ class SipcMessage
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.register_second(fetion)
|
9
|
-
body = %Q|<args><device machine-code="
|
9
|
+
body = %Q|<args><device machine-code="#{fetion.machine_code}" /><caps value="ff" /><events value="7f" /><user-info mobile-no="#{fetion.mobile_no}" user-id="#{fetion.uid}"><personal version="0" attributes="v4default" /><custom-config version="0" /><contact-list version="0" buddy-attributes="v4default" /></user-info><credentials domains="fetion.com.cn;m161.com.cn;www.ikuwa.cn;games.fetion.com.cn" /><presence><basic value="400" desc="" /></presence></args>|
|
10
10
|
sipc_create(:command => 'R', :F => fetion.sid, :I => 1, :Q => "#{fetion.next_alive} R", :A => %Q|Digest response="#{fetion.response}",algorithm="SHA1-sess-v4"|, :AK => 'ak-value', :body => body)
|
11
11
|
end
|
12
12
|
|
data/rfetion.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rfetion}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Richard Huang"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-29}
|
13
13
|
s.description = %q{rfetion is a ruby gem for China Mobile fetion service that you can send SMS free.}
|
14
14
|
s.email = %q{flyerhzm@gmail.com}
|
15
15
|
s.executables = ["rfetion", "rfetion"]
|
@@ -53,15 +53,21 @@ Gem::Specification.new do |s|
|
|
53
53
|
s.specification_version = 3
|
54
54
|
|
55
55
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
56
|
-
s.add_runtime_dependency(%q<guid>, [">= 0
|
56
|
+
s.add_runtime_dependency(%q<guid>, [">= 0"])
|
57
57
|
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
58
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<macaddr>, [">= 0"])
|
58
60
|
else
|
59
|
-
s.add_dependency(%q<guid>, [">= 0
|
61
|
+
s.add_dependency(%q<guid>, [">= 0"])
|
60
62
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
63
|
+
s.add_dependency(%q<json>, [">= 0"])
|
64
|
+
s.add_dependency(%q<macaddr>, [">= 0"])
|
61
65
|
end
|
62
66
|
else
|
63
|
-
s.add_dependency(%q<guid>, [">= 0
|
67
|
+
s.add_dependency(%q<guid>, [">= 0"])
|
64
68
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
69
|
+
s.add_dependency(%q<json>, [">= 0"])
|
70
|
+
s.add_dependency(%q<macaddr>, [">= 0"])
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
|
|
2
2
|
|
3
3
|
describe Fetion::BuddyList do
|
4
4
|
before :each do
|
5
|
-
@buddy_list = Fetion::BuddyList.new("1", "
|
5
|
+
@buddy_list = Fetion::BuddyList.new("1", "My friend")
|
6
6
|
@buddy_list.add_contact(Fetion::Contact.new(:uid => "226911221", :uri => "sip:572512981@fetion.com.cn;p=3544", :bid => "1", :status => "400"))
|
7
7
|
@buddy_list.add_contact(Fetion::Contact.new(:uid => "295098062", :uri => "sip:638993408@fetion.com.cn;p=2242", :bid => "1"))
|
8
8
|
@buddy_list.add_contact(Fetion::Contact.new(:uid => "579113578", :uri => "sip:838271744@fetion.com.cn;p=4805", :bid => "1"))
|
@@ -19,4 +19,13 @@ describe Fetion::BuddyList do
|
|
19
19
|
it "should get online contacts count" do
|
20
20
|
@buddy_list.online_contacts_count.should == 3
|
21
21
|
end
|
22
|
+
|
23
|
+
it "should to_json" do
|
24
|
+
buddy_list_json = @buddy_list.to_json
|
25
|
+
p buddy_list_json
|
26
|
+
buddy_list_json.should be_include %Q|"bid":"1"|
|
27
|
+
buddy_list_json.should be_include %Q|"name":"My friend"|
|
28
|
+
buddy_list_json.should be_include %Q|"total_contacts":7|
|
29
|
+
buddy_list_json.should be_include %Q|"online_contacts":3|
|
30
|
+
end
|
22
31
|
end
|
data/spec/rfetion/fetion_spec.rb
CHANGED
@@ -312,6 +312,7 @@ EOF
|
|
312
312
|
FakeWeb.register_uri(:post, "http://221.176.31.39/ht/sd.aspx?t=s&i=10", :body => response_body)
|
313
313
|
@fetion.get_contacts
|
314
314
|
@fetion.contacts.collect {|contact| contact.sid}.should == ["572512981", "638993408", nil, "926157269", nil, nil, "480867781", "793401629", "669700695", "660250260", "737769829", "760087520"]
|
315
|
+
@fetion.contacts.collect {|contact| contact.status}.should == ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "400", "0"]
|
315
316
|
end
|
316
317
|
|
317
318
|
it "should get received msg while get contacts" do
|
@@ -832,9 +833,10 @@ EOF
|
|
832
833
|
EOF
|
833
834
|
FakeWeb.register_uri(:get, "http://nav.fetion.com.cn/nav/GetPicCodeV4.aspx?algorithm=picc-PasswordErrorMax", :body => response_body)
|
834
835
|
actual_pic = @fetion.get_pic_certificate("picc-PasswordErrorMax")
|
835
|
-
expected_pic = PicCertificate.parse(Nokogiri::XML(response_body).root.xpath('/results/pic-certificate').first)
|
836
|
-
actual_pic.
|
836
|
+
expected_pic = PicCertificate.parse(Nokogiri::XML(response_body).root.xpath('/results/pic-certificate').first, 'picc-PasswordErrorMax')
|
837
|
+
actual_pic.pid.should == expected_pic.pid
|
837
838
|
actual_pic.pic.should == expected_pic.pic
|
839
|
+
actual_pic.algorithm.should == expected_pic.algorithm
|
838
840
|
end
|
839
841
|
end
|
840
842
|
end
|
@@ -48,6 +48,7 @@ L: 447
|
|
48
48
|
<args><device machine-code="B04B5DA2F5F1B8D01A76C0EBC841414C" /><caps value="ff" /><events value="7f" /><user-info mobile-no="15800681509" user-id="390937727"><personal version="0" attributes="v4default" /><custom-config version="0" /><contact-list version="0" buddy-attributes="v4default" /></user-info><credentials domains="fetion.com.cn;m161.com.cn;www.ikuwa.cn;games.fetion.com.cn" /><presence><basic value="400" desc="" /></presence></args>SIPP
|
49
49
|
EOF
|
50
50
|
sipc_message.gsub!("\n", "\r\n").chomp!
|
51
|
+
@fetion.machine_code = "B04B5DA2F5F1B8D01A76C0EBC841414C"
|
51
52
|
SipcMessage.register_second(@fetion).should == sipc_message
|
52
53
|
end
|
53
54
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 7
|
9
|
+
version: 0.5.7
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Richard Huang
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-29 00:00:00 +08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,9 +26,7 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
segments:
|
28
28
|
- 0
|
29
|
-
|
30
|
-
- 1
|
31
|
-
version: 0.1.1
|
29
|
+
version: "0"
|
32
30
|
type: :runtime
|
33
31
|
version_requirements: *id001
|
34
32
|
- !ruby/object:Gem::Dependency
|
@@ -43,6 +41,30 @@ dependencies:
|
|
43
41
|
version: "0"
|
44
42
|
type: :runtime
|
45
43
|
version_requirements: *id002
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: json
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
type: :runtime
|
55
|
+
version_requirements: *id003
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: macaddr
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
type: :runtime
|
67
|
+
version_requirements: *id004
|
46
68
|
description: rfetion is a ruby gem for China Mobile fetion service that you can send SMS free.
|
47
69
|
email: flyerhzm@gmail.com
|
48
70
|
executables:
|