tp-blather 0.8.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.
- data/.autotest +13 -0
- data/.gemtest +0 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +249 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +413 -0
- data/Rakefile +20 -0
- data/TODO.md +2 -0
- data/blather.gemspec +51 -0
- data/examples/certs/README +20 -0
- data/examples/certs/ca-bundle.crt +3987 -0
- data/examples/echo.rb +19 -0
- data/examples/execute.rb +17 -0
- data/examples/ping_pong.rb +38 -0
- data/examples/print_hierarchy.rb +77 -0
- data/examples/rosterprint.rb +15 -0
- data/examples/stream_only.rb +28 -0
- data/examples/trusted_echo.rb +21 -0
- data/examples/xmpp4r/echo.rb +36 -0
- data/lib/blather.rb +112 -0
- data/lib/blather/cert_store.rb +53 -0
- data/lib/blather/client.rb +95 -0
- data/lib/blather/client/client.rb +345 -0
- data/lib/blather/client/dsl.rb +320 -0
- data/lib/blather/client/dsl/pubsub.rb +174 -0
- data/lib/blather/core_ext/eventmachine.rb +125 -0
- data/lib/blather/core_ext/ipaddr.rb +20 -0
- data/lib/blather/errors.rb +69 -0
- data/lib/blather/errors/sasl_error.rb +44 -0
- data/lib/blather/errors/stanza_error.rb +110 -0
- data/lib/blather/errors/stream_error.rb +84 -0
- data/lib/blather/file_transfer.rb +107 -0
- data/lib/blather/file_transfer/ibb.rb +68 -0
- data/lib/blather/file_transfer/s5b.rb +114 -0
- data/lib/blather/jid.rb +141 -0
- data/lib/blather/roster.rb +118 -0
- data/lib/blather/roster_item.rb +146 -0
- data/lib/blather/stanza.rb +167 -0
- data/lib/blather/stanza/disco.rb +32 -0
- data/lib/blather/stanza/disco/capabilities.rb +161 -0
- data/lib/blather/stanza/disco/disco_info.rb +205 -0
- data/lib/blather/stanza/disco/disco_items.rb +134 -0
- data/lib/blather/stanza/iq.rb +144 -0
- data/lib/blather/stanza/iq/command.rb +339 -0
- data/lib/blather/stanza/iq/ibb.rb +86 -0
- data/lib/blather/stanza/iq/ping.rb +50 -0
- data/lib/blather/stanza/iq/query.rb +53 -0
- data/lib/blather/stanza/iq/roster.rb +185 -0
- data/lib/blather/stanza/iq/s5b.rb +208 -0
- data/lib/blather/stanza/iq/si.rb +415 -0
- data/lib/blather/stanza/iq/vcard.rb +149 -0
- data/lib/blather/stanza/message.rb +428 -0
- data/lib/blather/stanza/message/muc_user.rb +119 -0
- data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
- data/lib/blather/stanza/presence.rb +172 -0
- data/lib/blather/stanza/presence/c.rb +100 -0
- data/lib/blather/stanza/presence/muc.rb +35 -0
- data/lib/blather/stanza/presence/muc_user.rb +147 -0
- data/lib/blather/stanza/presence/status.rb +218 -0
- data/lib/blather/stanza/presence/subscription.rb +100 -0
- data/lib/blather/stanza/pubsub.rb +119 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
- data/lib/blather/stanza/pubsub/create.rb +65 -0
- data/lib/blather/stanza/pubsub/errors.rb +18 -0
- data/lib/blather/stanza/pubsub/event.rb +139 -0
- data/lib/blather/stanza/pubsub/items.rb +103 -0
- data/lib/blather/stanza/pubsub/publish.rb +103 -0
- data/lib/blather/stanza/pubsub/retract.rb +92 -0
- data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
- data/lib/blather/stanza/pubsub/subscription.rb +135 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
- data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
- data/lib/blather/stanza/pubsub_owner.rb +51 -0
- data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
- data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
- data/lib/blather/stanza/x.rb +416 -0
- data/lib/blather/stream.rb +266 -0
- data/lib/blather/stream/client.rb +32 -0
- data/lib/blather/stream/component.rb +39 -0
- data/lib/blather/stream/features.rb +70 -0
- data/lib/blather/stream/features/register.rb +38 -0
- data/lib/blather/stream/features/resource.rb +63 -0
- data/lib/blather/stream/features/sasl.rb +190 -0
- data/lib/blather/stream/features/session.rb +45 -0
- data/lib/blather/stream/features/tls.rb +29 -0
- data/lib/blather/stream/parser.rb +102 -0
- data/lib/blather/version.rb +3 -0
- data/lib/blather/xmpp_node.rb +94 -0
- data/spec/blather/client/client_spec.rb +687 -0
- data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
- data/spec/blather/client/dsl_spec.rb +266 -0
- data/spec/blather/errors/sasl_error_spec.rb +33 -0
- data/spec/blather/errors/stanza_error_spec.rb +129 -0
- data/spec/blather/errors/stream_error_spec.rb +108 -0
- data/spec/blather/errors_spec.rb +33 -0
- data/spec/blather/file_transfer_spec.rb +135 -0
- data/spec/blather/jid_spec.rb +87 -0
- data/spec/blather/roster_item_spec.rb +134 -0
- data/spec/blather/roster_spec.rb +107 -0
- data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
- data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
- data/spec/blather/stanza/iq/command_spec.rb +206 -0
- data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
- data/spec/blather/stanza/iq/ping_spec.rb +45 -0
- data/spec/blather/stanza/iq/query_spec.rb +64 -0
- data/spec/blather/stanza/iq/roster_spec.rb +139 -0
- data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
- data/spec/blather/stanza/iq/si_spec.rb +98 -0
- data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
- data/spec/blather/stanza/iq_spec.rb +61 -0
- data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
- data/spec/blather/stanza/message_spec.rb +282 -0
- data/spec/blather/stanza/presence/c_spec.rb +56 -0
- data/spec/blather/stanza/presence/muc_spec.rb +37 -0
- data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
- data/spec/blather/stanza/presence/status_spec.rb +144 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
- data/spec/blather/stanza/presence_spec.rb +125 -0
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
- data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
- data/spec/blather/stanza/pubsub/event_spec.rb +98 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
- data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
- data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
- data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +74 -0
- data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
- data/spec/blather/stanza/pubsub_spec.rb +68 -0
- data/spec/blather/stanza/x_spec.rb +231 -0
- data/spec/blather/stanza_spec.rb +134 -0
- data/spec/blather/stream/client_spec.rb +1090 -0
- data/spec/blather/stream/component_spec.rb +108 -0
- data/spec/blather/stream/parser_spec.rb +152 -0
- data/spec/blather/stream/ssl_spec.rb +32 -0
- data/spec/blather/xmpp_node_spec.rb +47 -0
- data/spec/blather_spec.rb +34 -0
- data/spec/fixtures/pubsub.rb +311 -0
- data/spec/spec_helper.rb +17 -0
- data/yard/templates/default/class/html/handlers.erb +18 -0
- data/yard/templates/default/class/setup.rb +10 -0
- data/yard/templates/default/class/text/handlers.erb +1 -0
- metadata +459 -0
data/examples/echo.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'blather/client'
|
|
5
|
+
|
|
6
|
+
when_ready { puts "Connected ! send messages to #{jid.stripped}." }
|
|
7
|
+
|
|
8
|
+
subscription :request? do |s|
|
|
9
|
+
write_to_stream s.approve!
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
message :chat?, :body => 'exit' do |m|
|
|
13
|
+
say m.from, 'Exiting ...'
|
|
14
|
+
shutdown
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
message :chat?, :body do |m|
|
|
18
|
+
say m.from, "You sent: #{m.body}"
|
|
19
|
+
end
|
data/examples/execute.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'blather/client'
|
|
5
|
+
|
|
6
|
+
message :chat?, :body => 'exit' do |m|
|
|
7
|
+
say m.from, 'Exiting ...'
|
|
8
|
+
shutdown
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
message :chat?, :body do |m|
|
|
12
|
+
begin
|
|
13
|
+
say m.from, eval(m.body)
|
|
14
|
+
rescue => e
|
|
15
|
+
say m.from, e.inspect
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'blather/client/dsl'
|
|
3
|
+
$stdout.sync = true
|
|
4
|
+
|
|
5
|
+
module Ping
|
|
6
|
+
extend Blather::DSL
|
|
7
|
+
def self.run; client.run; end
|
|
8
|
+
|
|
9
|
+
setup 'echo@jabber.local/ping', 'echo'
|
|
10
|
+
|
|
11
|
+
status :from => Blather::JID.new('echo@jabber.local/pong') do |s|
|
|
12
|
+
puts "serve!"
|
|
13
|
+
say s.from, 'ping'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
message :chat?, :body => 'pong' do |m|
|
|
17
|
+
puts "ping!"
|
|
18
|
+
say m.from, 'ping'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Pong
|
|
23
|
+
extend Blather::DSL
|
|
24
|
+
def self.run; client.run; end
|
|
25
|
+
|
|
26
|
+
setup 'echo@jabber.local/pong', 'echo'
|
|
27
|
+
message :chat?, :body => 'ping' do |m|
|
|
28
|
+
puts "pong!"
|
|
29
|
+
say m.from, 'pong'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
trap(:INT) { EM.stop }
|
|
34
|
+
trap(:TERM) { EM.stop }
|
|
35
|
+
EM.run do
|
|
36
|
+
Ping.run
|
|
37
|
+
Pong.run
|
|
38
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'blather'
|
|
3
|
+
|
|
4
|
+
class Object
|
|
5
|
+
begin
|
|
6
|
+
ObjectSpace.each_object(Class.new) {}
|
|
7
|
+
|
|
8
|
+
# Exclude this class unless it's a subclass of our supers and is defined.
|
|
9
|
+
# We check defined? in case we find a removed class that has yet to be
|
|
10
|
+
# garbage collected. This also fails for anonymous classes -- please
|
|
11
|
+
# submit a patch if you have a workaround.
|
|
12
|
+
def subclasses_of(*superclasses)
|
|
13
|
+
subclasses = []
|
|
14
|
+
|
|
15
|
+
superclasses.each do |sup|
|
|
16
|
+
ObjectSpace.each_object(class << sup; self; end) do |k|
|
|
17
|
+
if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
|
18
|
+
subclasses << k
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subclasses
|
|
24
|
+
end
|
|
25
|
+
rescue RuntimeError
|
|
26
|
+
# JRuby and any implementations which cannot handle the objectspace traversal
|
|
27
|
+
# above fall back to this implementation
|
|
28
|
+
def subclasses_of(*superclasses)
|
|
29
|
+
subclasses = []
|
|
30
|
+
|
|
31
|
+
superclasses.each do |sup|
|
|
32
|
+
ObjectSpace.each_object(Class) do |k|
|
|
33
|
+
if superclasses.any? { |superclass| k < superclass } &&
|
|
34
|
+
(k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
|
35
|
+
subclasses << k
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
subclasses.uniq!
|
|
39
|
+
end
|
|
40
|
+
subclasses
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Hash
|
|
46
|
+
def deep_merge(second)
|
|
47
|
+
# From: http://www.ruby-forum.com/topic/142809
|
|
48
|
+
# Author: Stefan Rusterholz
|
|
49
|
+
merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
|
50
|
+
self.merge(second, &merger)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
handlers = {}
|
|
55
|
+
(Object.subclasses_of(Blather::Stanza) + Object.subclasses_of(Blather::BlatherError)).each do |klass|
|
|
56
|
+
handlers = handlers.deep_merge klass.handler_hierarchy.inject('klass' => klass.to_s.gsub('Blather::', '')) { |h,k| {k.to_s => h} }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
level = 0
|
|
60
|
+
runner = proc do |k,v|
|
|
61
|
+
next if k == 'klass'
|
|
62
|
+
|
|
63
|
+
str = ''
|
|
64
|
+
if level > 0
|
|
65
|
+
(level - 1).times { str << '| ' }
|
|
66
|
+
str << '|- '
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
puts str+k
|
|
70
|
+
if Hash === v
|
|
71
|
+
level += 1
|
|
72
|
+
v.sort.each &runner
|
|
73
|
+
level -= 1
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
handlers.sort.each &runner
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Prints out each roster entry
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'blather/client'
|
|
7
|
+
|
|
8
|
+
when_ready do
|
|
9
|
+
roster.grouped.each do |group, items|
|
|
10
|
+
puts "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}"
|
|
11
|
+
items.each { |item| puts "- #{item.name} (#{item.jid})" }
|
|
12
|
+
puts
|
|
13
|
+
end
|
|
14
|
+
shutdown
|
|
15
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'blather'
|
|
5
|
+
|
|
6
|
+
trap(:INT) { EM.stop }
|
|
7
|
+
trap(:TERM) { EM.stop }
|
|
8
|
+
EM.run do
|
|
9
|
+
Blather::Stream::Client.start(Class.new {
|
|
10
|
+
attr_accessor :jid
|
|
11
|
+
|
|
12
|
+
def post_init(stream, jid = nil)
|
|
13
|
+
@stream = stream
|
|
14
|
+
self.jid = jid
|
|
15
|
+
|
|
16
|
+
@stream.send_data Blather::Stanza::Presence::Status.new
|
|
17
|
+
puts "Stream started!"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def receive_data(stanza)
|
|
21
|
+
@stream.send_data stanza.reply!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def unbind
|
|
25
|
+
puts "Stream ended!"
|
|
26
|
+
end
|
|
27
|
+
}.new, 'echo@jabber.local', 'echo')
|
|
28
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'blather/client'
|
|
5
|
+
|
|
6
|
+
setup 'chris@vines.local', 'test', 'vines.local', 5222, "./certs"
|
|
7
|
+
|
|
8
|
+
when_ready { puts "Connected ! send messages to #{jid.stripped}." }
|
|
9
|
+
|
|
10
|
+
subscription :request? do |s|
|
|
11
|
+
write_to_stream s.approve!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
message :chat?, :body => 'exit' do |m|
|
|
15
|
+
say m.from, 'Exiting ...'
|
|
16
|
+
shutdown
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
message :chat?, :body do |m|
|
|
20
|
+
say m.from, "You sent: #{m.body}"
|
|
21
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This bot will reply to every message it receives. To end the game, send 'exit'
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'xmpp4r/client'
|
|
7
|
+
include Jabber
|
|
8
|
+
|
|
9
|
+
# settings
|
|
10
|
+
if ARGV.length != 2
|
|
11
|
+
puts "Run with ./echo_thread.rb user@server/resource password"
|
|
12
|
+
exit 1
|
|
13
|
+
end
|
|
14
|
+
myJID = JID.new(ARGV[0])
|
|
15
|
+
myPassword = ARGV[1]
|
|
16
|
+
cl = Client.new(myJID)
|
|
17
|
+
cl.connect
|
|
18
|
+
cl.auth(myPassword)
|
|
19
|
+
cl.send(Presence.new)
|
|
20
|
+
puts "Connected ! send messages to #{myJID.strip.to_s}."
|
|
21
|
+
mainthread = Thread.current
|
|
22
|
+
cl.add_message_callback do |m|
|
|
23
|
+
if m.type != :error
|
|
24
|
+
m2 = Message.new(m.from, "You sent: #{m.body}")
|
|
25
|
+
m2.type = m.type
|
|
26
|
+
cl.send(m2)
|
|
27
|
+
if m.body == 'exit'
|
|
28
|
+
m2 = Message.new(m.from, "Exiting ...")
|
|
29
|
+
m2.type = m.type
|
|
30
|
+
cl.send(m2)
|
|
31
|
+
mainthread.wakeup
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
Thread.stop
|
|
36
|
+
cl.close
|
data/lib/blather.rb
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Require the necessary files
|
|
2
|
+
%w[
|
|
3
|
+
rubygems
|
|
4
|
+
eventmachine
|
|
5
|
+
niceogiri
|
|
6
|
+
ipaddr
|
|
7
|
+
digest/md5
|
|
8
|
+
digest/sha1
|
|
9
|
+
logger
|
|
10
|
+
openssl
|
|
11
|
+
girl_friday
|
|
12
|
+
|
|
13
|
+
active_support/core_ext/class/attribute
|
|
14
|
+
active_support/core_ext/object/blank
|
|
15
|
+
|
|
16
|
+
blather/core_ext/eventmachine
|
|
17
|
+
blather/core_ext/ipaddr
|
|
18
|
+
|
|
19
|
+
blather/cert_store
|
|
20
|
+
blather/errors
|
|
21
|
+
blather/errors/sasl_error
|
|
22
|
+
blather/errors/stanza_error
|
|
23
|
+
blather/errors/stream_error
|
|
24
|
+
blather/file_transfer
|
|
25
|
+
blather/file_transfer/ibb
|
|
26
|
+
blather/file_transfer/s5b
|
|
27
|
+
blather/jid
|
|
28
|
+
blather/roster
|
|
29
|
+
blather/roster_item
|
|
30
|
+
blather/xmpp_node
|
|
31
|
+
|
|
32
|
+
blather/stanza
|
|
33
|
+
blather/stanza/iq
|
|
34
|
+
blather/stanza/iq/command
|
|
35
|
+
blather/stanza/iq/ibb
|
|
36
|
+
blather/stanza/iq/ping
|
|
37
|
+
blather/stanza/iq/query
|
|
38
|
+
blather/stanza/iq/roster
|
|
39
|
+
blather/stanza/iq/s5b
|
|
40
|
+
blather/stanza/iq/si
|
|
41
|
+
blather/stanza/iq/vcard
|
|
42
|
+
blather/stanza/disco
|
|
43
|
+
blather/stanza/disco/disco_info
|
|
44
|
+
blather/stanza/disco/disco_items
|
|
45
|
+
blather/stanza/disco/capabilities
|
|
46
|
+
blather/stanza/message
|
|
47
|
+
blather/stanza/message/muc_user
|
|
48
|
+
blather/stanza/presence
|
|
49
|
+
blather/stanza/presence/c
|
|
50
|
+
blather/stanza/presence/status
|
|
51
|
+
blather/stanza/presence/subscription
|
|
52
|
+
blather/stanza/presence/muc
|
|
53
|
+
blather/stanza/presence/muc_user
|
|
54
|
+
|
|
55
|
+
blather/stanza/pubsub
|
|
56
|
+
blather/stanza/pubsub/affiliations
|
|
57
|
+
blather/stanza/pubsub/create
|
|
58
|
+
blather/stanza/pubsub/event
|
|
59
|
+
blather/stanza/pubsub/items
|
|
60
|
+
blather/stanza/pubsub/publish
|
|
61
|
+
blather/stanza/pubsub/retract
|
|
62
|
+
blather/stanza/pubsub/subscribe
|
|
63
|
+
blather/stanza/pubsub/subscription
|
|
64
|
+
blather/stanza/pubsub/subscriptions
|
|
65
|
+
blather/stanza/pubsub/unsubscribe
|
|
66
|
+
|
|
67
|
+
blather/stanza/pubsub_owner
|
|
68
|
+
blather/stanza/pubsub_owner/delete
|
|
69
|
+
blather/stanza/pubsub_owner/purge
|
|
70
|
+
|
|
71
|
+
blather/stanza/x
|
|
72
|
+
|
|
73
|
+
blather/stream
|
|
74
|
+
blather/stream/client
|
|
75
|
+
blather/stream/component
|
|
76
|
+
blather/stream/parser
|
|
77
|
+
blather/stream/features
|
|
78
|
+
blather/stream/features/resource
|
|
79
|
+
blather/stream/features/sasl
|
|
80
|
+
blather/stream/features/session
|
|
81
|
+
blather/stream/features/tls
|
|
82
|
+
blather/stream/features/register
|
|
83
|
+
].each { |r| require r }
|
|
84
|
+
|
|
85
|
+
module Blather
|
|
86
|
+
@@logger = nil
|
|
87
|
+
|
|
88
|
+
class << self
|
|
89
|
+
|
|
90
|
+
# Default logger level. Any internal call to log() will forward the log message to
|
|
91
|
+
# the default log level
|
|
92
|
+
attr_accessor :default_log_level
|
|
93
|
+
|
|
94
|
+
def logger
|
|
95
|
+
@@logger ||= Logger.new($stdout).tap {|logger| logger.level = Logger::INFO }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def logger=(logger)
|
|
99
|
+
@@logger = logger
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def default_log_level
|
|
103
|
+
@default_log_level ||= :debug # by default is debug (as it used to be)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def log(message)
|
|
107
|
+
logger.send self.default_log_level, message
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Blather
|
|
4
|
+
|
|
5
|
+
# An X509 certificate store that validates certificate trust chains.
|
|
6
|
+
# This uses the #{cert_directory}/*.crt files as the list of trusted root
|
|
7
|
+
# CA certificates.
|
|
8
|
+
class CertStore
|
|
9
|
+
@@certs = nil
|
|
10
|
+
@cert_directory = nil
|
|
11
|
+
|
|
12
|
+
def initialize(cert_directory)
|
|
13
|
+
@cert_directory = cert_directory
|
|
14
|
+
@store = OpenSSL::X509::Store.new
|
|
15
|
+
certs.each {|c| @store.add_cert(c) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Return true if the certificate is signed by a CA certificate in the
|
|
19
|
+
# store. If the certificate can be trusted, it's added to the store so
|
|
20
|
+
# it can be used to trust other certs.
|
|
21
|
+
def trusted?(pem)
|
|
22
|
+
if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
|
|
23
|
+
@store.verify(cert).tap do |trusted|
|
|
24
|
+
@store.add_cert(cert) if trusted rescue nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Return true if the domain name matches one of the names in the
|
|
30
|
+
# certificate. In other words, is the certificate provided to us really
|
|
31
|
+
# for the domain to which we think we're connected?
|
|
32
|
+
def domain?(pem, domain)
|
|
33
|
+
if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
|
|
34
|
+
OpenSSL::SSL.verify_certificate_identity(cert, domain) rescue false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Return the trusted root CA certificates installed in the @cert_directory. These
|
|
39
|
+
# certificates are used to start the trust chain needed to validate certs
|
|
40
|
+
# we receive from clients and servers.
|
|
41
|
+
def certs
|
|
42
|
+
unless @@certs
|
|
43
|
+
pattern = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
|
|
44
|
+
dir = @cert_directory
|
|
45
|
+
certs = Dir[File.join(dir, '*.crt')].map {|f| File.read(f) }
|
|
46
|
+
certs = certs.map {|c| c.scan(pattern) }.flatten
|
|
47
|
+
certs.map! {|c| OpenSSL::X509::Certificate.new(c) }
|
|
48
|
+
@@certs = certs.reject {|c| c.not_after < Time.now }
|
|
49
|
+
end
|
|
50
|
+
@@certs
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
require File.join(File.dirname(__FILE__), *%w[client dsl])
|
|
3
|
+
|
|
4
|
+
include Blather::DSL
|
|
5
|
+
|
|
6
|
+
options = {}
|
|
7
|
+
optparse = OptionParser.new do |opts|
|
|
8
|
+
opts.banner = "Run with #{$0} [options] user@server/resource password [host] [port]"
|
|
9
|
+
|
|
10
|
+
opts.on('-D', '--debug', 'Run in debug mode (you will see all XMPP communication)') do
|
|
11
|
+
options[:debug] = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
opts.on('-d', '--daemonize', 'Daemonize the process') do |daemonize|
|
|
15
|
+
options[:daemonize] = daemonize
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
opts.on('--pid=[PID]', 'Write the PID to this file') do |pid|
|
|
19
|
+
if !File.writable?(File.dirname(pid))
|
|
20
|
+
$stderr.puts "Unable to write log file to #{pid}"
|
|
21
|
+
exit 1
|
|
22
|
+
end
|
|
23
|
+
options[:pid] = pid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opts.on('--log=[LOG]', 'Write to the [LOG] file instead of stdout/stderr') do |log|
|
|
27
|
+
if !File.writable?(File.dirname(log))
|
|
28
|
+
$stderr.puts "Unable to write log file to #{log}"
|
|
29
|
+
exit 1
|
|
30
|
+
end
|
|
31
|
+
options[:log] = log
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
opts.on('--certs=[CERTS DIRECTORY]', 'The directory path where the trusted certificates are stored') do |certs|
|
|
35
|
+
if !File.directory?(certs)
|
|
36
|
+
$stderr.puts "The certs directory path (#{certs}) is no good."
|
|
37
|
+
exit 1
|
|
38
|
+
end
|
|
39
|
+
options[:certs] = certs
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
|
43
|
+
puts opts
|
|
44
|
+
exit
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
|
48
|
+
require 'yaml'
|
|
49
|
+
version = YAML.load_file File.join(File.dirname(__FILE__), %w[.. .. VERSION.yml])
|
|
50
|
+
puts "Blather v#{version[:major]}.#{version[:minor]}.#{version[:patch]}"
|
|
51
|
+
exit
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
optparse.parse!
|
|
55
|
+
|
|
56
|
+
at_exit do
|
|
57
|
+
unless client.setup?
|
|
58
|
+
if ARGV.length < 2
|
|
59
|
+
puts optparse
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
|
62
|
+
client.setup(*ARGV)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run(options)
|
|
66
|
+
$stdin.reopen "/dev/null"
|
|
67
|
+
|
|
68
|
+
if options[:log]
|
|
69
|
+
log = File.new(options[:log], 'a')
|
|
70
|
+
log.sync = options[:debug]
|
|
71
|
+
$stdout.reopen log
|
|
72
|
+
$stderr.reopen $stdout
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
Blather.logger.level = Logger::DEBUG if options[:debug]
|
|
76
|
+
|
|
77
|
+
trap(:INT) { EM.stop }
|
|
78
|
+
trap(:TERM) { EM.stop }
|
|
79
|
+
EM.run { client.run }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if options[:daemonize]
|
|
83
|
+
pid = fork do
|
|
84
|
+
Process.setsid
|
|
85
|
+
exit if fork
|
|
86
|
+
File.open(options[:pid], 'w') { |f| f << Process.pid } if options[:pid]
|
|
87
|
+
run options
|
|
88
|
+
FileUtils.rm(options[:pid]) if options[:pid]
|
|
89
|
+
end
|
|
90
|
+
::Process.detach pid
|
|
91
|
+
exit
|
|
92
|
+
else
|
|
93
|
+
run options
|
|
94
|
+
end
|
|
95
|
+
end
|