Permalink
Browse files

initial import

  • Loading branch information...
crapooze committed Apr 15, 2012
0 parents commit 86d7217de130f58b25a5e95ba57b88a32692fcea
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in em-xmpp.gemspec
+gemspec
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 crapooze
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
+# Em::Xmpp
+
+TODO: Write a gem description
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'em-xmpp'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install em-xmpp
+
+## Usage
+
+TODO: Write usage instructions here
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/em-xmpp/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["crapooze"]
+ gem.email = ["crapooze@gmail.com"]
+ gem.description = %q{XMPP client for event machine}
+ gem.summary = %q{Easy to write and to extend XMPP client}
+ gem.homepage = ""
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "em-xmpp"
+ gem.require_paths = ["lib"]
+ gem.version = Em::Xmpp::VERSION
+ gem.add_dependency "eventmachine"
+ gem.add_dependency "nokogiri"
+ gem.add_dependency "ruby-sasl"
+end
@@ -0,0 +1,9 @@
+require 'eventmachine'
+require "em-xmpp/version"
+require "em-xmpp/connection"
+
+module EM
+ module Xmpp
+ # Your code goes here...
+ end
+end
@@ -0,0 +1,76 @@
+=begin
+The code from this file was copied from Blather:
+
+
+Copyright (c) 2011 Jeff Smick
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+=end
+
+module EM::Xmpp
+ # An X509 certificate store that validates certificate trust chains.
+ # This uses the #{cert_directory}/*.crt files as the list of trusted root
+ # CA certificates.
+ class CertStore
+ @@certs = nil
+ @cert_directory = nil
+
+ def initialize(cert_directory)
+ @cert_directory = cert_directory
+ @store = OpenSSL::X509::Store.new
+ certs.each {|c| @store.add_cert(c) }
+ end
+
+ # Return true if the certificate is signed by a CA certificate in the
+ # store. If the certificate can be trusted, it's added to the store so
+ # it can be used to trust other certs.
+ def trusted?(pem)
+ if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
+ @store.verify(cert).tap do |trusted|
+ @store.add_cert(cert) if trusted rescue nil
+ end
+ end
+ end
+
+ # Return true if the domain name matches one of the names in the
+ # certificate. In other words, is the certificate provided to us really
+ # for the domain to which we think we're connected?
+ def domain?(pem, domain)
+ if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
+ OpenSSL::SSL.verify_certificate_identity(cert, domain) rescue false
+ end
+ end
+
+ # Return the trusted root CA certificates installed in the @cert_directory. These
+ # certificates are used to start the trust chain needed to validate certs
+ # we receive from clients and servers.
+ def certs
+ unless @@certs
+ pattern = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
+ dir = @cert_directory
+ certs = Dir[File.join(dir, '*.crt')].map {|f| File.read(f) }
+ certs = certs.map {|c| c.scan(pattern) }.flatten
+ certs.map! {|c| OpenSSL::X509::Certificate.new(c) }
+ @@certs = certs.reject {|c| c.not_after < Time.now }
+ end
+ @@certs
+ end
+ end
+end
@@ -0,0 +1,134 @@
+
+require 'em-xmpp/namespaces'
+require 'em-xmpp/connector'
+require 'em-xmpp/handler'
+require 'em-xmpp/jid'
+require 'em-xmpp/cert_store'
+require 'eventmachine'
+require 'base64'
+require 'digest/md5'
+
+module EM::Xmpp
+ class Connection < EM::Connection
+ include Namespaces
+ include Connector
+
+ attr_reader :jid, :pass
+
+ def initialize(jid, pass, mod=nil, cfg={})
+ @jid = jid
+ @pass = pass.dup.freeze
+ self.extend mod if mod
+ certdir = cfg[:certificates]
+ @certstore = if certdir
+ CertStore.new(certdir)
+ else
+ nil
+ end
+ end
+
+ def post_init
+ super
+ @handler = StreamNegotiation.new self
+ end
+
+ def stanza_start(node)
+ end
+
+ def stanza_end(node)
+ @handler.handle(node)
+ end
+
+ def unhandled_stanza(node)
+ raise RuntimeError, "did not handle node:\n#{node}"
+ end
+
+ def jid_received(jid)
+ @jid = JID.parse jid
+ end
+
+ def negotiation_finished
+ @pass = nil
+ @handler = Routine.new self
+ send_raw presence_stanza()
+ ready
+ end
+
+ def negotiation_failed(node)
+ raise RuntimeError, "could not negotiate a stream:\n#{node}"
+ end
+
+ def request_subscription(to)
+ send_raw(presence_stanza('to' => to, 'type'=> 'subscribe'))
+ end
+
+ def get_roster
+ send_raw(iq_stanza('from' => @jid.full) do
+ query('xmlns' => 'jabber:iq:roster')
+ end)
+ end
+
+ def send_message(to, body='')
+ send_raw(message_stanza('to' => to) do
+ body(body)
+ end)
+ end
+
+ #should add 'xml:lang'
+
+ def default_presence_config
+ {}
+ end
+
+ def default_message_config
+ {'to' => @jid.domain, 'id' => "em-xmpp.#{rand(65535)}"}
+ end
+
+ def default_iq_config
+ {'type' => 'get', 'id' => "em-xmpp.#{rand(65535)}"}
+ end
+
+ def presence_stanza(cfg={}, &blk)
+ cfg = default_presence_config.merge(cfg)
+ build_xml do
+ presence(cfg, &blk)
+ end
+ end
+
+ def message_stanza(cfg={}, &blk)
+ cfg = default_message_config.merge(cfg)
+ build_xml do
+ message(cfg, &blk)
+ end
+ end
+
+ def iq_stanza(cfg={}, &blk)
+ cfg = default_iq_config.merge(cfg)
+ build_xml do
+ iq(cfg, &blk)
+ end
+ end
+
+ %w{on on_exception on_presence on_iq on_message}.each do |meth|
+ define_method(meth) do |*args,&blk|
+ @handler.send meth, *args, &blk
+ end
+ end
+
+ def ready
+ end
+
+ def start_using_tls_and_reset_stream
+ bool = !! @certstore
+ start_tls(:verify_peer => bool)
+ restart_xml_stream
+ end
+
+ def ssl_verify_peer(pem)
+ @certstore.trusted?(pem).tap do |trusted|
+ close_connection unless trusted
+ end
+ end
+
+ end
+end
Oops, something went wrong.

0 comments on commit 86d7217

Please sign in to comment.