tp-blather 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|