xmpp4r_facebook 0.1 → 0.1.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.
- data/lib/xmpp4r_facebook.rb +145 -0
- metadata +5 -4
@@ -0,0 +1,145 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
require 'xmpp4r'
|
3
|
+
|
4
|
+
module Jabber
|
5
|
+
module SASL
|
6
|
+
class XFacebookPlatform < Base
|
7
|
+
def initialize(stream, api_key, access_token, secret_key)
|
8
|
+
super(stream)
|
9
|
+
challenge = {}
|
10
|
+
error = nil
|
11
|
+
@stream.send(generate_auth('X-FACEBOOK-PLATFORM')) { |reply|
|
12
|
+
if reply.name == 'challenge' and reply.namespace == NS_SASL
|
13
|
+
challenge = decode_challenge(reply.text)
|
14
|
+
else
|
15
|
+
error = reply.first_element(nil).name
|
16
|
+
end
|
17
|
+
true
|
18
|
+
}
|
19
|
+
raise error if error
|
20
|
+
|
21
|
+
@nonce = challenge['nonce']
|
22
|
+
@realm = challenge['realm']
|
23
|
+
@method = challenge['method']
|
24
|
+
@api_key = api_key
|
25
|
+
@access_token = access_token
|
26
|
+
@secret_key = secret_key
|
27
|
+
end
|
28
|
+
|
29
|
+
def decode_challenge(challenge)
|
30
|
+
text = Base64::decode64(challenge)
|
31
|
+
res = {}
|
32
|
+
state = :key
|
33
|
+
key = ''
|
34
|
+
value = ''
|
35
|
+
text.scan(/./) do |ch|
|
36
|
+
if state == :key
|
37
|
+
if ch == '='
|
38
|
+
state = :value
|
39
|
+
else
|
40
|
+
key += ch
|
41
|
+
end
|
42
|
+
elsif state == :value
|
43
|
+
if ch == '&'
|
44
|
+
# due to our home-made parsing of the challenge, the key could have
|
45
|
+
# leading whitespace. strip it, or that would break jabberd2 support.
|
46
|
+
key = key.strip
|
47
|
+
res[key] = value
|
48
|
+
key = ''
|
49
|
+
value = ''
|
50
|
+
state = :key
|
51
|
+
elsif ch == '"' and value == ''
|
52
|
+
state = :quote
|
53
|
+
else
|
54
|
+
value += ch
|
55
|
+
end
|
56
|
+
elsif state == :quote
|
57
|
+
if ch == '"'
|
58
|
+
state = :value
|
59
|
+
else
|
60
|
+
value += ch
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
# due to our home-made parsing of the challenge, the key could have
|
65
|
+
# leading whitespace. strip it, or that would break jabberd2 support.
|
66
|
+
key = key.strip
|
67
|
+
res[key] = value unless key == ''
|
68
|
+
Jabber::debuglog("SASL DIGEST-MD5 challenge:\n#{text}\n#{res.inspect}")
|
69
|
+
res
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# * Send a response
|
74
|
+
# * Wait for the server's challenge (which aren't checked)
|
75
|
+
# * Send a blind response to the server's challenge
|
76
|
+
def auth(password)
|
77
|
+
response2 = {}
|
78
|
+
response2['api_key'] = @api_key
|
79
|
+
response2['call_id'] = Time.new.tv_sec
|
80
|
+
response2['method'] = @method
|
81
|
+
response2['nonce'] = @nonce
|
82
|
+
response2['access_token'] = @access_token
|
83
|
+
response2['v'] ='1.0'
|
84
|
+
|
85
|
+
response_text = response2.collect { |k,v| "#{k}=#{v}" }.join('&')
|
86
|
+
#Jabber::debuglog("SASL DIGEST-MD5 response:\n#{response_text}\n#{response.inspect}")
|
87
|
+
|
88
|
+
r = REXML::Element.new('response')
|
89
|
+
r.add_namespace NS_SASL
|
90
|
+
r.text = Base64::encode64(response_text)
|
91
|
+
success_already = false
|
92
|
+
error = nil
|
93
|
+
@stream.send(r) { |reply|
|
94
|
+
if reply.name == 'success'
|
95
|
+
success_already = true
|
96
|
+
elsif reply.name != 'challenge'
|
97
|
+
error = reply.first_element(nil).name
|
98
|
+
end
|
99
|
+
true
|
100
|
+
}
|
101
|
+
|
102
|
+
return if success_already
|
103
|
+
raise error if error
|
104
|
+
|
105
|
+
# TODO: check the challenge from the server
|
106
|
+
|
107
|
+
r.text = nil
|
108
|
+
@stream.send(r) { |reply|
|
109
|
+
if reply.name != 'success'
|
110
|
+
error = reply.first_element(nil).name
|
111
|
+
end
|
112
|
+
true
|
113
|
+
}
|
114
|
+
|
115
|
+
raise error if error
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
##
|
121
|
+
# Function from RFC2831
|
122
|
+
def h(s); Digest::MD5.digest(s); end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Function from RFC2831
|
126
|
+
def hh(s); Digest::MD5.hexdigest(s); end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Calculate the value for the response field
|
130
|
+
def response_value(username, realm, digest_uri, passwd, nonce, cnonce, qop, authzid)
|
131
|
+
a1_h = h("#{username}:#{realm}:#{passwd}")
|
132
|
+
a1 = "#{a1_h}:#{nonce}:#{cnonce}"
|
133
|
+
if authzid
|
134
|
+
a1 += ":#{authzid}"
|
135
|
+
end
|
136
|
+
if qop == 'auth-int' || qop == 'auth-conf'
|
137
|
+
a2 = "AUTHENTICATE:#{digest_uri}:00000000000000000000000000000000"
|
138
|
+
else
|
139
|
+
a2 = "AUTHENTICATE:#{digest_uri}"
|
140
|
+
end
|
141
|
+
hh("#{hh(a1)}:#{nonce}:00000001:#{cnonce}:#{qop}:#{hh(a2)}")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmpp4r_facebook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-02-29 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: xmpp4r
|
16
|
-
requirement: &
|
16
|
+
requirement: &83866630 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,13 +21,14 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *83866630
|
25
25
|
description: Expansion XMPP4R to authenticate with Facebook Connect in Ruby
|
26
26
|
email: kissrobber@gmail.com
|
27
27
|
executables: []
|
28
28
|
extensions: []
|
29
29
|
extra_rdoc_files: []
|
30
|
-
files:
|
30
|
+
files:
|
31
|
+
- lib/xmpp4r_facebook.rb
|
31
32
|
homepage: https://github.com/kissrobber
|
32
33
|
licenses: []
|
33
34
|
post_install_message:
|