ln-xmpp4r 0.5
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/CHANGELOG +91 -0
- data/COPYING +340 -0
- data/LICENSE +59 -0
- data/README.rdoc +113 -0
- data/README_ruby19.txt +43 -0
- data/Rakefile +252 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/README +56 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +23 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +136 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/cube.xml +15 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/tower.xml +69 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +424 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.conf +11 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.rb +346 -0
- data/data/doc/xmpp4r/examples/advanced/getonline.rb +56 -0
- data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +315 -0
- data/data/doc/xmpp4r/examples/advanced/migrate.rb +88 -0
- data/data/doc/xmpp4r/examples/advanced/minimuc.rb +266 -0
- data/data/doc/xmpp4r/examples/advanced/pep-aggregator/index.xsl +235 -0
- data/data/doc/xmpp4r/examples/advanced/pep-aggregator/pep-aggregator.rb +147 -0
- data/data/doc/xmpp4r/examples/advanced/recvfile.rb +84 -0
- data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +129 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.conf +10 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.rb +72 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +51 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +43 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +10 -0
- data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +109 -0
- data/data/doc/xmpp4r/examples/advanced/xmpping.rb +146 -0
- data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +14 -0
- data/data/doc/xmpp4r/examples/basic/change_password.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/client.rb +70 -0
- data/data/doc/xmpp4r/examples/basic/component.rb +11 -0
- data/data/doc/xmpp4r/examples/basic/echo.rb +37 -0
- data/data/doc/xmpp4r/examples/basic/jabbersend.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/mass_sender.rb +68 -0
- data/data/doc/xmpp4r/examples/basic/muc_owner_config.rb +12 -0
- data/data/doc/xmpp4r/examples/basic/mucinfo.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +82 -0
- data/data/doc/xmpp4r/examples/basic/register.rb +42 -0
- data/data/doc/xmpp4r/examples/basic/remove_registration.rb +18 -0
- data/data/doc/xmpp4r/examples/basic/roster.rb +44 -0
- data/data/doc/xmpp4r/examples/basic/rosterprint.rb +50 -0
- data/data/doc/xmpp4r/examples/basic/rosterrename.rb +34 -0
- data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +171 -0
- data/data/doc/xmpp4r/examples/basic/send_vcard.rb +67 -0
- data/data/doc/xmpp4r/examples/basic/tune_client.rb +56 -0
- data/data/doc/xmpp4r/examples/basic/tune_server.rb +58 -0
- data/data/doc/xmpp4r/examples/basic/versionbot.rb +75 -0
- data/lib/xmpp4r.rb +116 -0
- data/lib/xmpp4r/base64.rb +32 -0
- data/lib/xmpp4r/bytestreams.rb +15 -0
- data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +319 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +257 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +31 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +54 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +152 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +86 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +198 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +65 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +79 -0
- data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +170 -0
- data/lib/xmpp4r/bytestreams/iq/si.rb +206 -0
- data/lib/xmpp4r/callbacks.rb +133 -0
- data/lib/xmpp4r/caps.rb +1 -0
- data/lib/xmpp4r/caps/c.rb +67 -0
- data/lib/xmpp4r/caps/helper/generator.rb +160 -0
- data/lib/xmpp4r/caps/helper/helper.rb +84 -0
- data/lib/xmpp4r/client.rb +344 -0
- data/lib/xmpp4r/command/helper/responder.rb +53 -0
- data/lib/xmpp4r/command/iq/command.rb +154 -0
- data/lib/xmpp4r/component.rb +103 -0
- data/lib/xmpp4r/connection.rb +223 -0
- data/lib/xmpp4r/dataforms.rb +5 -0
- data/lib/xmpp4r/dataforms/x/data.rb +297 -0
- data/lib/xmpp4r/debuglog.rb +63 -0
- data/lib/xmpp4r/delay.rb +5 -0
- data/lib/xmpp4r/delay/x/delay.rb +99 -0
- data/lib/xmpp4r/discovery.rb +8 -0
- data/lib/xmpp4r/discovery/helper/helper.rb +58 -0
- data/lib/xmpp4r/discovery/helper/responder.rb +165 -0
- data/lib/xmpp4r/discovery/iq/discoinfo.rb +211 -0
- data/lib/xmpp4r/discovery/iq/discoitems.rb +147 -0
- data/lib/xmpp4r/errors.rb +284 -0
- data/lib/xmpp4r/feature_negotiation.rb +5 -0
- data/lib/xmpp4r/feature_negotiation/iq/feature.rb +28 -0
- data/lib/xmpp4r/framework/base.rb +55 -0
- data/lib/xmpp4r/framework/bot.rb +148 -0
- data/lib/xmpp4r/httpbinding.rb +5 -0
- data/lib/xmpp4r/httpbinding/client.rb +275 -0
- data/lib/xmpp4r/idgenerator.rb +37 -0
- data/lib/xmpp4r/iq.rb +221 -0
- data/lib/xmpp4r/jid.rb +167 -0
- data/lib/xmpp4r/last.rb +2 -0
- data/lib/xmpp4r/last/helper/helper.rb +37 -0
- data/lib/xmpp4r/last/iq/last.rb +67 -0
- data/lib/xmpp4r/location.rb +2 -0
- data/lib/xmpp4r/location/helper/helper.rb +56 -0
- data/lib/xmpp4r/location/location.rb +179 -0
- data/lib/xmpp4r/message.rb +180 -0
- data/lib/xmpp4r/muc.rb +14 -0
- data/lib/xmpp4r/muc/helper/mucbrowser.rb +92 -0
- data/lib/xmpp4r/muc/helper/mucclient.rb +462 -0
- data/lib/xmpp4r/muc/helper/simplemucclient.rb +332 -0
- data/lib/xmpp4r/muc/iq/mucadmin.rb +23 -0
- data/lib/xmpp4r/muc/iq/mucadminitem.rb +20 -0
- data/lib/xmpp4r/muc/iq/mucowner.rb +15 -0
- data/lib/xmpp4r/muc/item.rb +143 -0
- data/lib/xmpp4r/muc/x/muc.rb +70 -0
- data/lib/xmpp4r/muc/x/mucuserinvite.rb +60 -0
- data/lib/xmpp4r/muc/x/mucuseritem.rb +36 -0
- data/lib/xmpp4r/presence.rb +232 -0
- data/lib/xmpp4r/pubsub.rb +8 -0
- data/lib/xmpp4r/pubsub/children/configuration.rb +86 -0
- data/lib/xmpp4r/pubsub/children/event.rb +49 -0
- data/lib/xmpp4r/pubsub/children/item.rb +35 -0
- data/lib/xmpp4r/pubsub/children/items.rb +53 -0
- data/lib/xmpp4r/pubsub/children/node_config.rb +48 -0
- data/lib/xmpp4r/pubsub/children/publish.rb +38 -0
- data/lib/xmpp4r/pubsub/children/retract.rb +41 -0
- data/lib/xmpp4r/pubsub/children/subscription.rb +62 -0
- data/lib/xmpp4r/pubsub/children/subscription_config.rb +67 -0
- data/lib/xmpp4r/pubsub/children/unsubscribe.rb +48 -0
- data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +129 -0
- data/lib/xmpp4r/pubsub/helper/nodehelper.rb +156 -0
- data/lib/xmpp4r/pubsub/helper/oauth_service_helper.rb +90 -0
- data/lib/xmpp4r/pubsub/helper/servicehelper.rb +456 -0
- data/lib/xmpp4r/pubsub/iq/pubsub.rb +19 -0
- data/lib/xmpp4r/query.rb +15 -0
- data/lib/xmpp4r/reliable.rb +168 -0
- data/lib/xmpp4r/rexmladdons.rb +157 -0
- data/lib/xmpp4r/roster.rb +7 -0
- data/lib/xmpp4r/roster/helper/roster.rb +522 -0
- data/lib/xmpp4r/roster/iq/roster.rb +215 -0
- data/lib/xmpp4r/roster/x/roster.rb +138 -0
- data/lib/xmpp4r/rpc.rb +2 -0
- data/lib/xmpp4r/rpc/helper/client.rb +123 -0
- data/lib/xmpp4r/rpc/helper/server.rb +74 -0
- data/lib/xmpp4r/rpc/helper/xmlrpcaddons.rb +67 -0
- data/lib/xmpp4r/rpc/iq/rpc.rb +23 -0
- data/lib/xmpp4r/sasl.rb +248 -0
- data/lib/xmpp4r/semaphore.rb +38 -0
- data/lib/xmpp4r/stream.rb +599 -0
- data/lib/xmpp4r/streamparser.rb +85 -0
- data/lib/xmpp4r/test/listener_mocker.rb +118 -0
- data/lib/xmpp4r/tune.rb +2 -0
- data/lib/xmpp4r/tune/helper/helper.rb +58 -0
- data/lib/xmpp4r/tune/tune.rb +113 -0
- data/lib/xmpp4r/vcard.rb +6 -0
- data/lib/xmpp4r/vcard/helper/vcard.rb +84 -0
- data/lib/xmpp4r/vcard/iq/vcard.rb +109 -0
- data/lib/xmpp4r/version.rb +7 -0
- data/lib/xmpp4r/version/helper/responder.rb +72 -0
- data/lib/xmpp4r/version/helper/simpleresponder.rb +44 -0
- data/lib/xmpp4r/version/iq/version.rb +105 -0
- data/lib/xmpp4r/x.rb +37 -0
- data/lib/xmpp4r/xhtml.rb +1 -0
- data/lib/xmpp4r/xhtml/html.rb +115 -0
- data/lib/xmpp4r/xmpp4r.rb +20 -0
- data/lib/xmpp4r/xmppelement.rb +168 -0
- data/lib/xmpp4r/xmppstanza.rb +162 -0
- data/setup.rb +1586 -0
- data/test/bytestreams/tc_ibb.rb +188 -0
- data/test/bytestreams/tc_socks5bytestreams.rb +114 -0
- data/test/caps/tc_helper.rb +158 -0
- data/test/dataforms/tc_data.rb +81 -0
- data/test/delay/tc_xdelay.rb +51 -0
- data/test/discovery/tc_responder.rb +91 -0
- data/test/last/tc_helper.rb +75 -0
- data/test/lib/assert_equal_xml.rb +14 -0
- data/test/lib/clienttester.rb +149 -0
- data/test/muc/tc_muc_mucclient.rb +834 -0
- data/test/muc/tc_muc_simplemucclient.rb +114 -0
- data/test/muc/tc_mucowner.rb +50 -0
- data/test/pubsub/tc_helper.rb +785 -0
- data/test/pubsub/tc_nodeconfig.rb +61 -0
- data/test/pubsub/tc_subscriptionconfig.rb +41 -0
- data/test/reliable/tc_disconnect_cleanup.rb +334 -0
- data/test/reliable/tc_disconnect_exception.rb +37 -0
- data/test/reliable/tc_listener_mocked_test.rb +68 -0
- data/test/reliable/tc_reliable_connection.rb +31 -0
- data/test/roster/tc_helper.rb +524 -0
- data/test/roster/tc_iqqueryroster.rb +173 -0
- data/test/roster/tc_xroster.rb +73 -0
- data/test/rpc/tc_helper.rb +96 -0
- data/test/tc_callbacks.rb +129 -0
- data/test/tc_class_names.rb +146 -0
- data/test/tc_client.rb +30 -0
- data/test/tc_errors.rb +146 -0
- data/test/tc_idgenerator.rb +30 -0
- data/test/tc_iq.rb +113 -0
- data/test/tc_iqquery.rb +31 -0
- data/test/tc_jid.rb +204 -0
- data/test/tc_message.rb +131 -0
- data/test/tc_presence.rb +150 -0
- data/test/tc_rexml.rb +139 -0
- data/test/tc_stream.rb +167 -0
- data/test/tc_streamComponent.rb +95 -0
- data/test/tc_streamError.rb +129 -0
- data/test/tc_streamSend.rb +59 -0
- data/test/tc_streamparser.rb +125 -0
- data/test/tc_xmppstanza.rb +135 -0
- data/test/ts_xmpp4r.rb +44 -0
- data/test/tune/tc_helper_recv.rb +82 -0
- data/test/tune/tc_helper_send.rb +74 -0
- data/test/tune/tc_tune.rb +79 -0
- data/test/vcard/tc_helper.rb +49 -0
- data/test/vcard/tc_iqvcard.rb +62 -0
- data/test/version/tc_helper.rb +60 -0
- data/test/version/tc_iqqueryversion.rb +97 -0
- data/test/xhtml/tc_html.rb +41 -0
- data/tools/gen_requires.bash +31 -0
- data/tools/xmpp4r-gemspec-test.rb +11 -0
- data/xmpp4r.gemspec +238 -0
- metadata +280 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'xmlrpc/server'
|
|
2
|
+
require 'xmlrpc/parser'
|
|
3
|
+
require 'xmlrpc/create'
|
|
4
|
+
require 'xmlrpc/config'
|
|
5
|
+
require 'xmlrpc/utils' # ParserWriterChooseMixin
|
|
6
|
+
|
|
7
|
+
require 'xmpp4r/dataforms/x/data'
|
|
8
|
+
require 'xmpp4r/rpc/iq/rpc'
|
|
9
|
+
require 'xmpp4r/rpc/helper/xmlrpcaddons'
|
|
10
|
+
|
|
11
|
+
module Jabber
|
|
12
|
+
module RPC
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# XMLRPC Server
|
|
16
|
+
class Server < XMLRPC::BasicServer
|
|
17
|
+
|
|
18
|
+
include XMLRPC::ParserWriterChooseMixin
|
|
19
|
+
include XMLRPC::ParseContentType
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# new - creates a new server
|
|
23
|
+
#
|
|
24
|
+
def initialize(stream,class_delim=".")
|
|
25
|
+
super(class_delim)
|
|
26
|
+
@stream = stream
|
|
27
|
+
@stream.add_iq_callback(120,"Helpers::RPCServer") { |iq|
|
|
28
|
+
if iq.type == :set and iq.type != :result
|
|
29
|
+
handle_iq(iq)
|
|
30
|
+
true
|
|
31
|
+
else
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# handles incoming iqs
|
|
39
|
+
# iq:: [Jabber::IQ] - the jabber iq
|
|
40
|
+
def handle_iq(iq)
|
|
41
|
+
if iq.type == :set
|
|
42
|
+
if iq.query.kind_of?(IqQueryRPC)
|
|
43
|
+
data = iq.query
|
|
44
|
+
response = IqQueryRPC.new
|
|
45
|
+
data.elements.each { |rpc|
|
|
46
|
+
if rpc
|
|
47
|
+
response.typed_add(handle_rpc_requests(rpc))
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
respiq = iq.answer(false)
|
|
52
|
+
respiq.type = :result
|
|
53
|
+
respiq.add(response)
|
|
54
|
+
@stream.send(respiq)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# handles the rpc requests
|
|
63
|
+
# takes rpcdata:: [String]
|
|
64
|
+
def handle_rpc_requests(rpcdata)
|
|
65
|
+
resp = process(rpcdata.to_s)
|
|
66
|
+
if resp == nil or resp.size <= 0
|
|
67
|
+
raise Jabber::ErrorResponse.new(:forbidden)
|
|
68
|
+
else
|
|
69
|
+
return resp
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end # RPCServer
|
|
73
|
+
end # Helpers
|
|
74
|
+
end # Jabber
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require "xmlrpc/parser"
|
|
2
|
+
require "xmlrpc/create"
|
|
3
|
+
require "xmlrpc/config"
|
|
4
|
+
require "xmlrpc/utils" # ParserWriterChooseMixin
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module XMLRPC
|
|
8
|
+
class Create
|
|
9
|
+
|
|
10
|
+
# Avoids warnings
|
|
11
|
+
remove_method(:methodCall)
|
|
12
|
+
remove_method(:methodResponse)
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# create a Method Call
|
|
16
|
+
# name:: [String] name of the method
|
|
17
|
+
# params:: [Array] params of the method as a array
|
|
18
|
+
def methodCall(name, *params)
|
|
19
|
+
name = name.to_s
|
|
20
|
+
|
|
21
|
+
if name !~ /[a-zA-Z0-9_.:\/]+/
|
|
22
|
+
raise ArgumentError, "Wrong XML-RPC method-name"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
parameter = params.collect { |param|
|
|
26
|
+
@writer.ele("param", conv2value(param))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
tree = @writer.document(
|
|
30
|
+
@writer.ele("methodCall",
|
|
31
|
+
@writer.tag("methodName", name),
|
|
32
|
+
@writer.ele("params", *parameter)
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@writer.document_to_str(tree) + "\n"
|
|
37
|
+
end
|
|
38
|
+
##
|
|
39
|
+
# create a response to a method call
|
|
40
|
+
# is_ret:: [TrueClass] is this a return (true) or a error (false)
|
|
41
|
+
# params:: [Array] a array of params
|
|
42
|
+
|
|
43
|
+
def methodResponse(is_ret, *params)
|
|
44
|
+
|
|
45
|
+
if is_ret
|
|
46
|
+
begin
|
|
47
|
+
resp = params.collect do |param|
|
|
48
|
+
@writer.ele("param", conv2value(param))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
resp = [@writer.ele("params", *resp)]
|
|
52
|
+
rescue Exception => e
|
|
53
|
+
error = XMLRPC::FaultException.new(XMLRPC::BasicServer::ERR_UNCAUGHT_EXCEPTION, "Uncaught exception '#{e.message}' serialising params into response")
|
|
54
|
+
resp = @writer.ele("fault", conv2value(error.to_h))
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
if params.size != 1 or params[0] === XMLRPC::FaultException
|
|
58
|
+
raise ArgumentError, "no valid fault-structure given"
|
|
59
|
+
end
|
|
60
|
+
resp = @writer.ele("fault", conv2value(params[0].to_h))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
tree = @writer.document(@writer.ele("methodResponse", resp))
|
|
64
|
+
@writer.document_to_str(tree) + "\n"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
|
4
|
+
|
|
5
|
+
require 'xmpp4r/query'
|
|
6
|
+
|
|
7
|
+
module Jabber
|
|
8
|
+
module RPC
|
|
9
|
+
class IqQueryRPC < IqQuery
|
|
10
|
+
NS_RPC = 'jabber:iq:rpc'
|
|
11
|
+
name_xmlns 'query', NS_RPC
|
|
12
|
+
|
|
13
|
+
# TODO: Is typed_add with a String right here?
|
|
14
|
+
def typed_add(e)
|
|
15
|
+
if e.kind_of? String
|
|
16
|
+
typed_add(REXML::Document.new(e).root)
|
|
17
|
+
else
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/xmpp4r/sasl.rb
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
|
4
|
+
|
|
5
|
+
require 'digest/md5'
|
|
6
|
+
require 'xmpp4r/base64'
|
|
7
|
+
|
|
8
|
+
module Jabber
|
|
9
|
+
##
|
|
10
|
+
# Helpers for SASL authentication (RFC2222)
|
|
11
|
+
#
|
|
12
|
+
# You might not need to use them directly, they are
|
|
13
|
+
# invoked by Jabber::Client#auth
|
|
14
|
+
module SASL
|
|
15
|
+
NS_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Factory function to obtain a SASL helper for the specified mechanism
|
|
19
|
+
def SASL.new(stream, mechanism)
|
|
20
|
+
case mechanism
|
|
21
|
+
when 'DIGEST-MD5'
|
|
22
|
+
DigestMD5.new(stream)
|
|
23
|
+
when 'PLAIN'
|
|
24
|
+
Plain.new(stream)
|
|
25
|
+
when 'ANONYMOUS'
|
|
26
|
+
Anonymous.new(stream)
|
|
27
|
+
else
|
|
28
|
+
raise "Unknown SASL mechanism: #{mechanism}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# SASL mechanism base class (stub)
|
|
34
|
+
class Base
|
|
35
|
+
def initialize(stream)
|
|
36
|
+
@stream = stream
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def generate_auth(mechanism, text=nil)
|
|
42
|
+
auth = REXML::Element.new 'auth'
|
|
43
|
+
auth.add_namespace NS_SASL
|
|
44
|
+
auth.attributes['mechanism'] = mechanism
|
|
45
|
+
auth.text = text
|
|
46
|
+
auth
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def generate_nonce
|
|
50
|
+
Digest::MD5.hexdigest(Time.new.to_f.to_s)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# SASL PLAIN authentication helper (RFC2595)
|
|
56
|
+
class Plain < Base
|
|
57
|
+
##
|
|
58
|
+
# Authenticate via sending password in clear-text
|
|
59
|
+
def auth(password)
|
|
60
|
+
auth_text = "#{@stream.jid.strip}\x00#{@stream.jid.node}\x00#{password}"
|
|
61
|
+
error = nil
|
|
62
|
+
@stream.send(generate_auth('PLAIN', Base64::encode64(auth_text).gsub(/\s/, ''))) { |reply|
|
|
63
|
+
if reply.name != 'success'
|
|
64
|
+
error = reply.first_element(nil).name
|
|
65
|
+
end
|
|
66
|
+
true
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
raise error if error
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
##
|
|
74
|
+
# SASL Anonymous authentication helper
|
|
75
|
+
class Anonymous < Base
|
|
76
|
+
##
|
|
77
|
+
# Authenticate by sending nothing with the ANONYMOUS token
|
|
78
|
+
def auth(password)
|
|
79
|
+
auth_text = "#{@stream.jid.node}"
|
|
80
|
+
error = nil
|
|
81
|
+
@stream.send(generate_auth('ANONYMOUS', Base64::encode64(auth_text).gsub(/\s/, ''))) { |reply|
|
|
82
|
+
if reply.name != 'success'
|
|
83
|
+
error = reply.first_element(nil).name
|
|
84
|
+
end
|
|
85
|
+
true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
raise error if error
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# SASL DIGEST-MD5 authentication helper (RFC2831)
|
|
94
|
+
class DigestMD5 < Base
|
|
95
|
+
##
|
|
96
|
+
# Sends the wished auth mechanism and wait for a challenge
|
|
97
|
+
#
|
|
98
|
+
# (proceed with DigestMD5#auth)
|
|
99
|
+
def initialize(stream)
|
|
100
|
+
super
|
|
101
|
+
|
|
102
|
+
challenge = {}
|
|
103
|
+
error = nil
|
|
104
|
+
@stream.send(generate_auth('DIGEST-MD5')) { |reply|
|
|
105
|
+
if reply.name == 'challenge' and reply.namespace == NS_SASL
|
|
106
|
+
challenge = decode_challenge(reply.text)
|
|
107
|
+
else
|
|
108
|
+
error = reply.first_element(nil).name
|
|
109
|
+
end
|
|
110
|
+
true
|
|
111
|
+
}
|
|
112
|
+
raise error if error
|
|
113
|
+
|
|
114
|
+
@nonce = challenge['nonce']
|
|
115
|
+
@realm = challenge['realm']
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def decode_challenge(challenge)
|
|
119
|
+
text = Base64::decode64(challenge)
|
|
120
|
+
res = {}
|
|
121
|
+
|
|
122
|
+
state = :key
|
|
123
|
+
key = ''
|
|
124
|
+
value = ''
|
|
125
|
+
text.scan(/./) do |ch|
|
|
126
|
+
if state == :key
|
|
127
|
+
if ch == '='
|
|
128
|
+
state = :value
|
|
129
|
+
else
|
|
130
|
+
key += ch
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
elsif state == :value
|
|
134
|
+
if ch == ','
|
|
135
|
+
# due to our home-made parsing of the challenge, the key could have
|
|
136
|
+
# leading whitespace. strip it, or that would break jabberd2 support.
|
|
137
|
+
key = key.strip
|
|
138
|
+
res[key] = value
|
|
139
|
+
key = ''
|
|
140
|
+
value = ''
|
|
141
|
+
state = :key
|
|
142
|
+
elsif ch == '"' and value == ''
|
|
143
|
+
state = :quote
|
|
144
|
+
else
|
|
145
|
+
value += ch
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
elsif state == :quote
|
|
149
|
+
if ch == '"'
|
|
150
|
+
state = :value
|
|
151
|
+
else
|
|
152
|
+
value += ch
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
# due to our home-made parsing of the challenge, the key could have
|
|
157
|
+
# leading whitespace. strip it, or that would break jabberd2 support.
|
|
158
|
+
key = key.strip
|
|
159
|
+
res[key] = value unless key == ''
|
|
160
|
+
|
|
161
|
+
Jabber::debuglog("SASL DIGEST-MD5 challenge:\n#{text}\n#{res.inspect}")
|
|
162
|
+
|
|
163
|
+
res
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
##
|
|
167
|
+
# * Send a response
|
|
168
|
+
# * Wait for the server's challenge (which aren't checked)
|
|
169
|
+
# * Send a blind response to the server's challenge
|
|
170
|
+
def auth(password)
|
|
171
|
+
response = {}
|
|
172
|
+
response['nonce'] = @nonce
|
|
173
|
+
response['charset'] = 'utf-8'
|
|
174
|
+
response['username'] = @stream.jid.node
|
|
175
|
+
response['realm'] = @realm || @stream.jid.domain
|
|
176
|
+
response['cnonce'] = generate_nonce
|
|
177
|
+
response['nc'] = '00000001'
|
|
178
|
+
response['qop'] = 'auth'
|
|
179
|
+
response['digest-uri'] = "xmpp/#{@stream.jid.domain}"
|
|
180
|
+
response['response'] = response_value(@stream.jid.node, @stream.jid.domain, response['digest-uri'], password, @nonce, response['cnonce'], response['qop'], response['authzid'])
|
|
181
|
+
response.each { |key,value|
|
|
182
|
+
unless %w(nc qop response charset).include? key
|
|
183
|
+
response[key] = "\"#{value}\""
|
|
184
|
+
end
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
response_text = response.collect { |k,v| "#{k}=#{v}" }.join(',')
|
|
188
|
+
Jabber::debuglog("SASL DIGEST-MD5 response:\n#{response_text}\n#{response.inspect}")
|
|
189
|
+
|
|
190
|
+
r = REXML::Element.new('response')
|
|
191
|
+
r.add_namespace NS_SASL
|
|
192
|
+
r.text = Base64::encode64(response_text).gsub(/\s/, '')
|
|
193
|
+
|
|
194
|
+
success_already = false
|
|
195
|
+
error = nil
|
|
196
|
+
@stream.send(r) { |reply|
|
|
197
|
+
if reply.name == 'success'
|
|
198
|
+
success_already = true
|
|
199
|
+
elsif reply.name != 'challenge'
|
|
200
|
+
error = reply.first_element(nil).name
|
|
201
|
+
end
|
|
202
|
+
true
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return if success_already
|
|
206
|
+
raise error if error
|
|
207
|
+
|
|
208
|
+
# TODO: check the challenge from the server
|
|
209
|
+
|
|
210
|
+
r.text = nil
|
|
211
|
+
@stream.send(r) { |reply|
|
|
212
|
+
if reply.name != 'success'
|
|
213
|
+
error = reply.first_element(nil).name
|
|
214
|
+
end
|
|
215
|
+
true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
raise error if error
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private
|
|
222
|
+
|
|
223
|
+
##
|
|
224
|
+
# Function from RFC2831
|
|
225
|
+
def h(s); Digest::MD5.digest(s); end
|
|
226
|
+
##
|
|
227
|
+
# Function from RFC2831
|
|
228
|
+
def hh(s); Digest::MD5.hexdigest(s); end
|
|
229
|
+
|
|
230
|
+
##
|
|
231
|
+
# Calculate the value for the response field
|
|
232
|
+
def response_value(username, realm, digest_uri, passwd, nonce, cnonce, qop, authzid)
|
|
233
|
+
a1_h = h("#{username}:#{realm}:#{passwd}")
|
|
234
|
+
a1 = "#{a1_h}:#{nonce}:#{cnonce}"
|
|
235
|
+
if authzid
|
|
236
|
+
a1 += ":#{authzid}"
|
|
237
|
+
end
|
|
238
|
+
if qop == 'auth-int' || qop == 'auth-conf'
|
|
239
|
+
a2 = "AUTHENTICATE:#{digest_uri}:00000000000000000000000000000000"
|
|
240
|
+
else
|
|
241
|
+
a2 = "AUTHENTICATE:#{digest_uri}"
|
|
242
|
+
end
|
|
243
|
+
hh("#{hh(a1)}:#{nonce}:00000001:#{cnonce}:#{qop}:#{hh(a2)}")
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
|
4
|
+
|
|
5
|
+
module Jabber
|
|
6
|
+
##
|
|
7
|
+
# This class implements semaphore for threads synchronization.
|
|
8
|
+
class Semaphore
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# Initialize new semaphore
|
|
12
|
+
#
|
|
13
|
+
# val:: [Integer] number of threads, that can enter to section
|
|
14
|
+
def initialize(val=0)
|
|
15
|
+
@tickets = val
|
|
16
|
+
@lock = Mutex.new
|
|
17
|
+
@cond = ConditionVariable.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Waits until are available some free tickets
|
|
22
|
+
def wait
|
|
23
|
+
@lock.synchronize {
|
|
24
|
+
@cond.wait(@lock) while !(@tickets > 0)
|
|
25
|
+
@tickets -= 1
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Unlocks guarded section, increments number of free tickets
|
|
31
|
+
def run
|
|
32
|
+
@lock.synchronize {
|
|
33
|
+
@tickets += 1
|
|
34
|
+
@cond.signal
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|