jabber4r-revive 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +5 -4
  2. data/.rspec +3 -3
  3. data/.travis.yml +7 -7
  4. data/CHANGELOG +11 -1
  5. data/Gemfile +3 -3
  6. data/README.md +29 -29
  7. data/Rakefile +70 -70
  8. data/jabber4r-revive.gemspec +25 -25
  9. data/lib/jabber4r.rb +38 -33
  10. data/lib/jabber4r/bosh.rb +21 -0
  11. data/lib/jabber4r/bosh/authentication.rb +13 -0
  12. data/lib/jabber4r/bosh/authentication/non_sasl.rb +219 -0
  13. data/lib/jabber4r/bosh/authentication/sasl.rb +239 -0
  14. data/lib/jabber4r/bosh/session.rb +144 -0
  15. data/lib/jabber4r/connection.rb +259 -258
  16. data/lib/jabber4r/debugger.rb +60 -60
  17. data/lib/jabber4r/jid.rb +20 -19
  18. data/lib/jabber4r/protocol.rb +249 -257
  19. data/lib/jabber4r/protocol/authentication.rb +14 -0
  20. data/lib/jabber4r/protocol/authentication/non_sasl.rb +138 -0
  21. data/lib/jabber4r/protocol/authentication/sasl.rb +88 -0
  22. data/lib/jabber4r/protocol/iq.rb +259 -259
  23. data/lib/jabber4r/protocol/message.rb +245 -245
  24. data/lib/jabber4r/protocol/parsed_xml_element.rb +207 -207
  25. data/lib/jabber4r/protocol/presence.rb +160 -160
  26. data/lib/jabber4r/protocol/xml_element.rb +143 -143
  27. data/lib/jabber4r/rexml_1.8_patch.rb +15 -15
  28. data/lib/jabber4r/roster.rb +38 -38
  29. data/lib/jabber4r/session.rb +615 -615
  30. data/lib/jabber4r/version.rb +10 -3
  31. data/spec/lib/jabber4r/bosh/authentication/non_sasl_spec.rb +79 -0
  32. data/spec/lib/jabber4r/bosh/authentication/sasl_spec.rb +42 -0
  33. data/spec/lib/jabber4r/bosh/session_spec.rb +406 -0
  34. data/spec/lib/jabber4r/bosh_spec.rb +0 -0
  35. data/spec/lib/jabber4r/connection_spec.rb +174 -174
  36. data/spec/lib/jabber4r/debugger_spec.rb +35 -35
  37. data/spec/lib/jabber4r/jid_spec.rb +197 -197
  38. data/spec/lib/jabber4r/protocol/authentication/non_sasl_spec.rb +79 -0
  39. data/spec/lib/jabber4r/protocol/authentication/sasl_spec.rb +42 -0
  40. data/spec/spec_helper.rb +11 -11
  41. data/spec/support/mocks/tcp_socket_mock.rb +8 -8
  42. metadata +61 -45
  43. data/Gemfile.lock +0 -45
  44. data/lib/jabber4r/bosh_session.rb +0 -224
  45. data/spec/lib/jabber4r/bosh_session_spec.rb +0 -150
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
- .rvmrc
2
-
3
- tmp/
4
- pkg/
1
+ .rvmrc
2
+ Gemfile.lock
3
+
4
+ tmp/
5
+ pkg/
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
- --color
2
- --format progress
3
- --order random
1
+ --color
2
+ --format progress
3
+ --order random
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.2
4
- - 1.9.3
5
- branches:
6
- only:
7
- - master
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ branches:
6
+ only:
7
+ - master
8
8
  script: bundle exec rspec
data/CHANGELOG CHANGED
@@ -1,15 +1,25 @@
1
1
 
2
+ v0.10.0
3
+ - 2013/07/08: fix(changelog) fixed version recognition (Strech (aka Sergey Fedorov))
4
+ - 2013/07/05: feature(bosh) added authentication via sasl and non-sasl technology (Strech (aka Sergey Fedorov))
5
+ - 2013/07/02: fix(rfc) added 'version' attribute to plain open stream tag (Strech (aka Sergey Fedorov))
6
+ - 2013/06/28: chore(gemspec) removed Gemfile.lock (Strech (aka Sergey Fedorov))
7
+ - 2013/06/28: style(protocol) removed debug information (Strech (aka Sergey Fedorov))
8
+ - 2013/06/28: refactor(all) change host to domain (Aelphy)
9
+ - 2013/06/26: style(all) debug methods added (Strech (aka Sergey Fedorov))
10
+
2
11
  v0.9.0
12
+ - 2013/06/26: Release 0.9.0 (Strech (aka Sergey Fedorov))
3
13
  - 2013/06/26: feature(changelog) added changelog file (Strech (aka Sergey Fedorov))
4
14
  - 2013/06/26: Jabber::BoshSession : Modified to_json method (Strech (aka Sergey Fedorov))
5
15
  - 2013/06/25: Jabber::BoshSession : XMPP over BOSH (XEP-0206) (Strech (aka Sergey Fedorov))
6
16
  - 2013/06/20: Jabber::Connection : Change method parse_failure (Strech (aka Sergey Fedorov))
7
17
  - 2013/06/20: Jabber::Connection : Refactoring (Strech (aka Sergey Fedorov))
8
18
  - 2013/06/20: Rspec : Socket mock changed. Jabber::Connection : Specs for #send (Strech (aka Sergey Fedorov))
19
+ - 2013/06/20: Jabber::Connection : add_filter and remove_filter refactoring (Strech (aka Sergey Fedorov))
9
20
  - 2013/06/20: Rspec : Change rspec dummy text (Strech (aka Sergey Fedorov))
10
21
  - 2013/06/20: Jabber::Debugger : Added (Strech (aka Sergey Fedorov))
11
22
  - 2013/06/20: Jabber : Moved up on one level (Strech (aka Sergey Fedorov))
12
- - 2013/06/20: Jabber::Connection : add_filter and remove_filter refactoring (Strech (aka Sergey Fedorov))
13
23
  - 2013/06/20: F (Strech (aka Sergey Fedorov))
14
24
  - 2013/06/20: F (Strech (aka Sergey Fedorov))
15
25
  - 2013/06/19: Jabber::Connection : New method force_close! added (Strech (aka Sergey Fedorov))
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md CHANGED
@@ -1,29 +1,29 @@
1
- # Jabber4r (revive)
2
-
3
- Original [README](http://rubydoc.info/gems/jabber4r/file/README) and original [jabber4r web-site](http://jabber4r.rubyforge.org/)
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'jabber4r-revive'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install jabber4r-revive
18
-
19
- ## Usage
20
-
21
- TODO: Write usage instructions here
22
-
23
- ## Contributing
24
-
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
1
+ # Jabber4r (revive)
2
+
3
+ Original [README](http://rubydoc.info/gems/jabber4r/file/README) and original [jabber4r web-site](http://jabber4r.rubyforge.org/)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jabber4r-revive'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jabber4r-revive
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile CHANGED
@@ -1,71 +1,71 @@
1
- # coding: utf-8
2
-
3
- require "bundler/gem_tasks"
4
- require "pty"
5
-
6
- # ============================== Support =======================================
7
-
8
- ROOT_PATH = File.expand_path("..", __FILE__)
9
- VERSION_PATH = File.join(ROOT_PATH, "lib", "jabber4r", "version.rb")
10
- CHANGELOG_PATH = File.join(ROOT_PATH, "CHANGELOG")
11
-
12
- # get current version from version.rb file
13
- def current_version
14
- version = File.read(VERSION_PATH).gsub(/[^\d\.]+/, "").strip.chomp
15
- end
16
-
17
- # get released version from git
18
- def released_version
19
- /\Av([\d\.]+)\z/ === `git describe --tags --abbrev=0 2>/dev/null || echo 'v0.0.0'`.chomp.strip
20
-
21
- $1
22
- end
23
-
24
- # run +cmd+ in subprocess, redirect its stdout to parent's stdout
25
- def spawn(cmd, stdout = STDOUT)
26
- puts ">> #{cmd}"
27
-
28
- cmd += ' 2>&1'
29
- PTY.spawn cmd do |r, w, pid|
30
- begin
31
- r.sync
32
- r.each_char { |chr| stdout.write(chr) }
33
- rescue Errno::EIO => e
34
- # simply ignoring this
35
- ensure
36
- ::Process.wait pid
37
- end
38
- end
39
- abort "#{cmd} failed" unless $? && $?.exitstatus == 0
40
- end
41
-
42
- # =============================== Tasks ========================================
43
-
44
- namespace :version do
45
- task :current do
46
- puts current_version
47
- end
48
-
49
- desc "Release new version"
50
- task release: [:changelog, :commit, :tag]
51
-
52
- desc "Add new version to git repo"
53
- task :commit do
54
- spawn "git add '#{VERSION_PATH}'"
55
- spawn "git diff --cached --exit-code > /dev/null || git commit -m \"Release #{current_version}\" || echo -n"
56
- end
57
-
58
- desc "Add git tag for new version"
59
- task :tag do
60
- spawn "git tag v#{current_version}"
61
- end
62
-
63
- desc "Generate file CHANGELOG"
64
- task :changelog do
65
- spawn "changelogger changelog '#{ROOT_PATH}' --top_version='v#{current_version}' > '#{CHANGELOG_PATH}'"
66
- spawn "git add '#{CHANGELOG_PATH}'"
67
- end
68
- end
69
-
70
- desc "Show current version"
1
+ # coding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+ require "pty"
5
+
6
+ # ============================== Support =======================================
7
+
8
+ ROOT_PATH = File.expand_path("..", __FILE__)
9
+ VERSION_PATH = File.join(ROOT_PATH, "lib", "jabber4r", "version.rb")
10
+ CHANGELOG_PATH = File.join(ROOT_PATH, "CHANGELOG")
11
+
12
+ # get current version from version.rb file
13
+ def current_version
14
+ version = File.read(VERSION_PATH).match(/VERSION \= \"(\d+\.\d+\.\d+)\"/)[1].strip.chomp
15
+ end
16
+
17
+ # get released version from git
18
+ def released_version
19
+ /\Av([\d\.]+)\z/ === `git describe --tags --abbrev=0 2>/dev/null || echo 'v0.0.0'`.chomp.strip
20
+
21
+ $1
22
+ end
23
+
24
+ # run +cmd+ in subprocess, redirect its stdout to parent's stdout
25
+ def spawn(cmd, stdout = STDOUT)
26
+ puts ">> #{cmd}"
27
+
28
+ cmd += ' 2>&1'
29
+ PTY.spawn cmd do |r, w, pid|
30
+ begin
31
+ r.sync
32
+ r.each_char { |chr| stdout.write(chr) }
33
+ rescue Errno::EIO => e
34
+ # simply ignoring this
35
+ ensure
36
+ ::Process.wait pid
37
+ end
38
+ end
39
+ abort "#{cmd} failed" unless $? && $?.exitstatus == 0
40
+ end
41
+
42
+ # =============================== Tasks ========================================
43
+
44
+ namespace :version do
45
+ task :current do
46
+ puts current_version
47
+ end
48
+
49
+ desc "Release new version"
50
+ task release: [:changelog, :commit, :tag]
51
+
52
+ desc "Add new version to git repo"
53
+ task :commit do
54
+ spawn "git add '#{VERSION_PATH}'"
55
+ spawn "git diff --cached --exit-code > /dev/null || git commit -m \"Release #{current_version}\" || echo -n"
56
+ end
57
+
58
+ desc "Add git tag for new version"
59
+ task :tag do
60
+ spawn "git tag v#{current_version}"
61
+ end
62
+
63
+ desc "Generate file CHANGELOG"
64
+ task :changelog do
65
+ spawn "changelogger changelog '#{ROOT_PATH}' --top_version='v#{current_version}' > '#{CHANGELOG_PATH}'"
66
+ spawn "git add '#{CHANGELOG_PATH}'"
67
+ end
68
+ end
69
+
70
+ desc "Show current version"
71
71
  task version: "version:current"
@@ -1,25 +1,25 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "jabber4r/version"
5
-
6
- Gem::Specification.new do |gem|
7
- gem.name = "jabber4r-revive"
8
- gem.version = Jabber::VERSION
9
- gem.authors = ["Richard Kilmer", "Sergey Fedorov"]
10
- gem.email = ["rich@infoether.com", "strech_ftf@mail.ru"]
11
- gem.description = "The purpose of this library is to allow Ruby applications to talk to a Jabber IM system. Jabber is an open-source instant messaging service, which can be learned about at http://www.jabber.org"
12
- gem.summary = "Read more http://jabber4r.rubyforge.org"
13
- gem.homepage = "https://github.com/Strech/jabber4r-revive"
14
-
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
19
-
20
- gem.add_dependency "ox"
21
-
22
- gem.add_development_dependency "rspec"
23
- gem.add_development_dependency "webmock"
24
- gem.add_development_dependency "changelogger"
25
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "jabber4r/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "jabber4r-revive"
8
+ gem.version = Jabber::VERSION
9
+ gem.authors = ["Richard Kilmer", "Sergey Fedorov"]
10
+ gem.email = ["rich@infoether.com", "strech_ftf@mail.ru"]
11
+ gem.description = "The purpose of this library is to allow Ruby applications to talk to a Jabber IM system. Jabber is an open-source instant messaging service, which can be learned about at http://www.jabber.org"
12
+ gem.summary = "Read more http://jabber4r.rubyforge.org"
13
+ gem.homepage = "https://github.com/Strech/jabber4r-revive"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "ox", "~> 2.0.4"
21
+
22
+ gem.add_development_dependency "rspec", "~> 2.13.0"
23
+ gem.add_development_dependency "webmock", "~> 1.11.0"
24
+ gem.add_development_dependency "changelogger", "~> 0.0.3"
25
+ end
data/lib/jabber4r.rb CHANGED
@@ -1,33 +1,38 @@
1
- # License: see LICENSE.txt
2
- # Jabber4R - Jabber Instant Messaging Library for Ruby
3
- # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
4
-
5
-
6
- # The Jabber module is the main namespace for all Jabber modules
7
- # and classes.
8
- module Jabber
9
- DEBUG = false
10
-
11
- # Public: Should raise if connection was force closed
12
- class ConnectionForceCloseError < StandardError; end
13
-
14
- # Public: Should raise if received XML data is malformed
15
- class XMLMalformedError < StandardError; end
16
-
17
- # Public: Should raise if authentication failed
18
- class AuthenticationError < StandardError; end
19
- end
20
-
21
- require "jabber4r/debugger"
22
- require "jabber4r/session"
23
- require "jabber4r/bosh_session"
24
- require "jabber4r/protocol"
25
- require "jabber4r/connection"
26
- require "jabber4r/protocol/iq"
27
- require "jabber4r/protocol/presence"
28
- require "jabber4r/protocol/message"
29
- require "jabber4r/protocol/xml_element"
30
- require "jabber4r/protocol/parsed_xml_element"
31
- require "jabber4r/roster"
32
- require "jabber4r/jid"
33
- require "jabber4r/vcard"
1
+ # License: see LICENSE.txt
2
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
3
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
4
+
5
+
6
+ # The Jabber module is the main namespace for all Jabber modules
7
+ # and classes.
8
+ module Jabber
9
+ DEBUG = false
10
+
11
+ # Public: Should raise if connection was force closed
12
+ class ConnectionForceCloseError < StandardError; end
13
+
14
+ # Public: Should raise if received XML data is malformed
15
+ class XMLMalformedError < StandardError; end
16
+
17
+ # Public: Should raise if authentication failed
18
+ class AuthenticationError < StandardError; end
19
+ end
20
+
21
+ require "jabber4r/debugger"
22
+
23
+ require "jabber4r/protocol"
24
+ require "jabber4r/connection"
25
+
26
+ require "jabber4r/protocol/iq"
27
+ require "jabber4r/protocol/presence"
28
+ require "jabber4r/protocol/message"
29
+ require "jabber4r/protocol/xml_element"
30
+ require "jabber4r/protocol/parsed_xml_element"
31
+ require "jabber4r/protocol/authentication"
32
+
33
+ require "jabber4r/jid"
34
+ require "jabber4r/bosh"
35
+ require "jabber4r/session"
36
+
37
+ require "jabber4r/roster"
38
+ require "jabber4r/vcard"
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+ # Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
7
+
8
+ module Jabber
9
+ module Bosh
10
+ # Public: Default connection options
11
+ DEFAULTS = {
12
+ domain: "localhost",
13
+ port: 5280,
14
+ bind_uri: "/http-bind",
15
+ use_sasl: true
16
+ }.freeze
17
+ end
18
+ end
19
+
20
+ require "jabber4r/bosh/authentication"
21
+ require "jabber4r/bosh/session"
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+ # Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
7
+
8
+ module Jabber::Bosh
9
+ module Authentication; end
10
+ end
11
+
12
+ require "jabber4r/bosh/authentication/sasl"
13
+ require "jabber4r/bosh/authentication/non_sasl"
@@ -0,0 +1,219 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+ # Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
7
+
8
+ require "ox"
9
+
10
+ module Jabber::Bosh::Authentication
11
+ # This class provides Non-SASL authentication for BOSH session
12
+ class NonSASL
13
+ # Public: Instance of Jabber::Bosh::Session
14
+ attr_reader :session
15
+
16
+ # Public: Opened stream identifier
17
+ attr_reader :stream_id
18
+
19
+ def initialize(session)
20
+ @session = session
21
+ end
22
+
23
+ def authenticate(jid, password)
24
+ open_stream
25
+
26
+ pass_authentication(jid, password)
27
+ end
28
+
29
+ # Internal: Send open stream command to jabber server
30
+ #
31
+ # Raises XMLMalformedError
32
+ # Returns boolean
33
+ def open_stream
34
+ body = Ox::Element.new("body").tap do |element|
35
+ element[:xmlns] = "http://jabber.org/protocol/httpbind"
36
+ element[:content] = "text/xml; charset=utf-8"
37
+ element[:rid] = session.generate_next_rid
38
+ element[:to] = session.domain
39
+ element[:secure] = true
40
+ element[:wait] = 60
41
+ element[:hold] = 1
42
+ end
43
+
44
+ Jabber.debug(%Q[Open (rid="#{body.rid}") new session])
45
+
46
+ response = session.post(Ox.dump body)
47
+ xml = Ox.parse(response.body.tr("'", '"'))
48
+
49
+ [:sid, :authid].each do |m|
50
+ raise Jabber::XMLMalformedError,
51
+ "Couldn't find <body /> attribute [#{m}]" if xml[m].nil?
52
+ end
53
+
54
+ session.sid, @stream_id = xml.sid, xml.authid
55
+
56
+ true
57
+ end
58
+
59
+ # Internal: Send login request to jabber server
60
+ #
61
+ # jid - Jabber::JID the jid of jabber user
62
+ # password - String the password of jabber user
63
+ #
64
+ # Raises TypeError
65
+ # Raises XMLMalformedError
66
+ # Returns boolean
67
+ def pass_authentication(jid, password)
68
+ raise TypeError,
69
+ "Jabber::JID expected, but #{jid.class} was given" unless jid.is_a?(Jabber::JID)
70
+
71
+ body = Ox::Element.new("body").tap do |element|
72
+ element[:xmlns] = 'http://jabber.org/protocol/httpbind'
73
+ element[:content] = "text/xml; charset=utf-8"
74
+ element[:rid] = session.generate_next_rid
75
+ element[:sid] = session.sid
76
+
77
+ element << Query.new(jid, password, stream_id: stream_id, mechanism: :digest).to_ox
78
+ end
79
+
80
+ Jabber.debug(%Q[Authenticate {Non-SASL} (rid="#{body.rid}" sid="#{body.sid}") in opened session] +
81
+ %Q[ as #{session.jid.node}/#{session.jid.resource}])
82
+
83
+ response = session.post(Ox.dump body)
84
+ xml = Ox.parse(response.body.tr("'", '"'))
85
+
86
+ raise Jabber::XMLMalformedError, "Couldn't find xml tag <iq/>" if xml.locate("iq").empty?
87
+ return false unless xml.iq[:type] == "result"
88
+
89
+ true
90
+ end
91
+
92
+ private
93
+ class Query
94
+ MECHANISMS = [:plain, :digest].freeze
95
+
96
+ attr_reader :jid, :password
97
+ attr_reader :stream_id, :mechanism
98
+
99
+ # Public: Creates new Non-SASL authentication object
100
+ #
101
+ # jid - [Jabber::JID|String] the jid of jabber server user
102
+ # password - String the user password
103
+ # options - Hash the authentication options (default: Empty hash)
104
+ # :stream_id - String the stream identifier (authid)
105
+ # :mechanism - Symbol the name of mechnism to use
106
+ #
107
+ # Examples
108
+ #
109
+ # non_sasl = Jabber::Protocol::Authentication::NonSASL.new("strech@localhost/res-1", "my-pass-phrase")
110
+ # non_sasl.plain? # => true
111
+ # non_sasl.to_xml # =>
112
+ #
113
+ # <iq type="set" id="...">
114
+ # <query xmlns="jabber:iq:auth">
115
+ # <username>strech</username>
116
+ # <password>my-pass-phrase</password>
117
+ # <resource>res-1</resource>
118
+ # </query>
119
+ # </iq>
120
+ def initialize(jid, password, options = {})
121
+ raise TypeError,
122
+ "Class(Jabber::JID) or Class(String) expected," +
123
+ " but #{jid.class} was given" unless jid.is_a?(Jabber::JID) || jid.is_a?(String)
124
+
125
+ @jid = jid.is_a?(Jabber::JID) ? jid : Jabber::JID.new(jid)
126
+ @password = password
127
+
128
+ @mechanism = options.fetch(:mechanism, :plain)
129
+ @stream_id = options.fetch(:stream_id) if digest?
130
+
131
+ raise ArgumentError,
132
+ "Unknown authentication mechanism '#{mechanism}'," +
133
+ " available is [#{MECHANISMS * ", "}]" unless MECHANISMS.include?(mechanism)
134
+ end
135
+
136
+ # Public: Is NonSASL object is for plain authentication
137
+ #
138
+ # Returns boolean
139
+ def plain?
140
+ mechanism == :plain
141
+ end
142
+
143
+ # Public: Is NonSASL object is for digest authentication
144
+ #
145
+ # Returns boolean
146
+ def digest?
147
+ mechanism == :digest
148
+ end
149
+
150
+ # Public: Create XML string from NonSASL object
151
+ #
152
+ # Returns String
153
+ def dump
154
+ Ox.dump(send mechanism)
155
+ end
156
+ alias :to_xml :dump
157
+
158
+ # Public: Create Ox::Element from NonSASL object
159
+ #
160
+ # Returns Ox::Element
161
+ def to_ox
162
+ send(mechanism)
163
+ end
164
+
165
+ private
166
+ # Internal: Make xml object for plain authentication mechanism
167
+ #
168
+ # Returns Ox:Element
169
+ def plain
170
+ query = Ox::Element.new("query").tap do |element|
171
+ element[:xmlns] = "jabber:iq:auth"
172
+
173
+ element << (Ox::Element.new("username") << jid.node)
174
+ element << (Ox::Element.new("password") << password)
175
+ element << (Ox::Element.new("resource") << jid.resource)
176
+ end
177
+
178
+ build_iq(query)
179
+ end
180
+
181
+ # Internal: Make xml object for digest authentication mechanism
182
+ #
183
+ # Returns Ox:Element
184
+ def digest
185
+ query = Ox::Element.new("query").tap do |element|
186
+ element[:xmlns] = "jabber:iq:auth"
187
+
188
+ digest_password = self.class.generate_digest(stream_id, password)
189
+
190
+ element << (Ox::Element.new("username") << jid.node)
191
+ element << (Ox::Element.new("digest") << digest_password)
192
+ element << (Ox::Element.new("resource") << jid.resource)
193
+ end
194
+
195
+ build_iq(query)
196
+ end
197
+
198
+ # Internal: The root iq stanza for authentication
199
+ #
200
+ # Returns Ox:Element
201
+ def build_iq(query)
202
+ Ox::Element.new("iq").tap do |element|
203
+ element[:xmlns] = "jabber:client"
204
+ element[:type] = "set"
205
+ element[:id] = Jabber.gen_random_id
206
+
207
+ element << query
208
+ end
209
+ end
210
+
211
+ # Internal: Generate hex string consist of concatination stream_id and password
212
+ #
213
+ # Returns String
214
+ def self.generate_digest(stream_id, password)
215
+ Digest::SHA1.hexdigest([stream_id, password].join)
216
+ end
217
+ end
218
+ end
219
+ end