tor 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -10,10 +10,13 @@ Features
10
10
 
11
11
  * Supports checking whether Tor is installed in the user's current `PATH`,
12
12
  and if it is, returning the version number.
13
+ * Supports parsing Tor configuration files and looking up the values of
14
+ particular options.
13
15
  * Supports querying and controlling a locally-running Tor process using the
14
16
  [Tor Control Protocol (TC)][TC] over a socket connection.
15
17
  * Supports querying the [Tor DNS Exit List (DNSEL)][TorDNSEL] to determine
16
18
  whether a particular host is a Tor exit node or not.
19
+ * Compatible with Ruby 1.8.7+, Ruby 1.9.x, and JRuby 1.4/1.5.
17
20
 
18
21
  Examples
19
22
  --------
@@ -26,7 +29,22 @@ Examples
26
29
  Tor.available? #=> true
27
30
  Tor.version #=> "0.2.1.25"
28
31
 
29
- ### Obtaining information about a running Tor process
32
+ ### Parsing the Tor configuration file (1)
33
+
34
+ torrc = Tor::Config.load("/etc/tor/torrc")
35
+
36
+ ### Parsing the Tor configuration file (2)
37
+
38
+ Tor::Config.open("/etc/tor/torrc") do |torrc|
39
+ puts "Tor SOCKS port: #{torrc['SocksPort']}"
40
+ puts "Tor control port: #{torrc['ControlPort']}"
41
+ puts "Tor exit policy:"
42
+ torrc.each('ExitPolicy') do |key, value|
43
+ puts " #{value}"
44
+ end
45
+ end
46
+
47
+ ### Communicating with a running Tor process
30
48
 
31
49
  Tor::Controller.connect(:port => 9051) do |tor|
32
50
  puts "Tor version: #{tor.version}"
@@ -47,6 +65,7 @@ Dependencies
47
65
  ------------
48
66
 
49
67
  * [Ruby](http://ruby-lang.org/) (>= 1.8.7) or (>= 1.8.1 with [Backports][])
68
+ * [Tor](https://www.torproject.org/download.html.en) (>= 0.2.1)
50
69
 
51
70
  Installation
52
71
  ------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
data/lib/tor.rb CHANGED
@@ -17,10 +17,33 @@ end
17
17
  ##
18
18
  # @see https://www.torproject.org/
19
19
  module Tor
20
+ autoload :Config, 'tor/config'
20
21
  autoload :Controller, 'tor/control'
21
22
  autoload :DNSEL, 'tor/dnsel'
22
23
  autoload :VERSION, 'tor/version'
23
24
 
25
+ ##
26
+ # Returns `true` if the Tor process is running locally, `false` otherwise.
27
+ #
28
+ # This works by attempting to establish a Tor Control Protocol (TC)
29
+ # connection to the standard control port 9051 on `localhost`. If Tor
30
+ # hasn't been configured with the `ControlPort 9051` option, this will
31
+ # return `false`.
32
+ #
33
+ # @example
34
+ # Tor.running? #=> false
35
+ #
36
+ # @return [Boolean]
37
+ # @since 0.1.2
38
+ def self.running?
39
+ begin
40
+ Tor::Controller.new.quit
41
+ true
42
+ rescue Errno::ECONNREFUSED
43
+ false
44
+ end
45
+ end
46
+
24
47
  ##
25
48
  # Returns `true` if Tor is available, `false` otherwise.
26
49
  #
@@ -0,0 +1,103 @@
1
+ module Tor
2
+ ##
3
+ # Tor configuration.
4
+ #
5
+ # @example Parsing a Tor configuration file (1)
6
+ # torrc = Tor::Config.load("/etc/tor/torrc")
7
+ #
8
+ # @example Parsing a Tor configuration file (2)
9
+ # Tor::Config.open("/etc/tor/torrc") do |torrc|
10
+ # puts "Tor SOCKS port: #{torrc['SocksPort']}"
11
+ # puts "Tor control port: #{torrc['ControlPort']}"
12
+ # puts "Tor exit policy:"
13
+ # torrc.each('ExitPolicy') do |key, value|
14
+ # puts " #{value}"
15
+ # end
16
+ # end
17
+ #
18
+ # @see https://www.torproject.org/tor-manual.html.en
19
+ # @since 0.1.2
20
+ class Config
21
+ CONFDIR = '/etc/tor' unless defined?(CONFDIR)
22
+
23
+ ##
24
+ # Opens a Tor configuration file.
25
+ #
26
+ # @param [String, #to_s] filename
27
+ # @param [Hash{Symbol => Object}] options
28
+ # @yield [config]
29
+ # @yieldparam [Config] config
30
+ # @return [Config]
31
+ def self.open(filename, options = {}, &block)
32
+ if block_given?
33
+ block.call(self.load(filename, options))
34
+ else
35
+ self.load(filename, options)
36
+ end
37
+ end
38
+
39
+ ##
40
+ # Loads the configuration options from a Tor configuration file.
41
+ #
42
+ # @param [String, #to_s] filename
43
+ # @param [Hash{Symbol => Object}] options
44
+ # @return [Config]
45
+ def self.load(filename, options = {})
46
+ self.new(options) do |config|
47
+ File.open(filename.to_s, 'rb') do |file|
48
+ file.each_line do |line|
49
+ case line = line.strip.chomp.strip
50
+ when '' then next # skip empty lines
51
+ when /^#/ then next # skip comments
52
+ else line = line.split('#').first.strip
53
+ end
54
+ # TODO: support for unquoting and unescaping values
55
+ config << line.split(/\s+/, 2)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ ##
62
+ # @param [Hash{Symbol => Object}] options
63
+ # @yield [config]
64
+ # @yieldparam [Config] config
65
+ def initialize(options = {}, &block)
66
+ @lines, @options = [], options.dup
67
+ block.call(self) if block_given?
68
+ end
69
+
70
+ ##
71
+ # Appends a new configuration option.
72
+ #
73
+ # @param [Array(String, String)]
74
+ # @return [Config]
75
+ def <<(kv)
76
+ @lines << kv
77
+ self
78
+ end
79
+
80
+ ##
81
+ # Looks up the last value of a particular configuration option.
82
+ #
83
+ # @param [String, Regexp] key
84
+ # @return [String]
85
+ def [](key)
86
+ values = each(key).map(&:last)
87
+ values.empty? ? nil : values.last
88
+ end
89
+
90
+ ##
91
+ # Enumerates configuration options.
92
+ #
93
+ # @param [String, Regexp] key
94
+ # @yield [key, value]
95
+ # @yieldparam [String] key
96
+ # @yieldparam [String] value
97
+ # @return [Enumerator]
98
+ def each(key = nil, &block)
99
+ return enum_for(:each, key) unless block_given?
100
+ key ? @lines.find_all { |k, v| key === k }.each(&block) : @lines.each(&block)
101
+ end
102
+ end
103
+ end
@@ -82,9 +82,9 @@ module Tor
82
82
  # Returns `true` if the controller connection is active.
83
83
  #
84
84
  # @example
85
- # tor.connected? #=> true
85
+ # tor.connected? #=> true
86
86
  # tor.close
87
- # tor.connected? #=> false
87
+ # tor.connected? #=> false
88
88
  #
89
89
  # @return [Boolean]
90
90
  def connected?
@@ -119,19 +119,57 @@ module Tor
119
119
  #
120
120
  # @return [void]
121
121
  def quit
122
- send_command(:quit)
122
+ send_line('QUIT')
123
123
  reply = read_reply
124
124
  close
125
125
  reply
126
126
  end
127
127
 
128
+ ##
129
+ # Returns information about the authentication method required by the
130
+ # Tor process.
131
+ #
132
+ # This command may be used before authenticating.
133
+ #
134
+ # @example
135
+ # C: PROTOCOLINFO
136
+ # S: 250-PROTOCOLINFO 1
137
+ # S: 250-AUTH METHODS=NULL
138
+ # S: 250-VERSION Tor="0.2.1.25"
139
+ # S: 250 OK
140
+ #
141
+ # @example
142
+ # tor.authentication_method #=> nil
143
+ # tor.authentication_method #=> :hashedpassword
144
+ # tor.authentication_method #=> :cookie
145
+ #
146
+ # @return [Symbol]
147
+ # @since 0.1.2
148
+ def authentication_method
149
+ @authentication_method ||= begin
150
+ method = nil
151
+ send_line('PROTOCOLINFO')
152
+ loop do
153
+ # TODO: support for reading multiple authentication methods
154
+ case reply = read_reply
155
+ when /^250-AUTH METHODS=(\w*)/
156
+ method = $1.strip.downcase.to_sym
157
+ method = method.eql?(:null) ? nil : method
158
+ when /^250-/ then next
159
+ when '250 OK' then break
160
+ end
161
+ end
162
+ method
163
+ end
164
+ end
165
+
128
166
  ##
129
167
  # Returns `true` if the controller connection has been authenticated.
130
168
  #
131
169
  # @example
132
- # tor.authenticated? #=> false
170
+ # tor.authenticated? #=> false
133
171
  # tor.authenticate
134
- # tor.authenticated? #=> true
172
+ # tor.authenticated? #=> true
135
173
  #
136
174
  # @return [Boolean]
137
175
  def authenticated?
@@ -169,7 +207,7 @@ module Tor
169
207
  # S: 250 OK
170
208
  #
171
209
  # @example
172
- # tor.version #=> "0.2.1.25"
210
+ # tor.version #=> "0.2.1.25"
173
211
  #
174
212
  # @return [String]
175
213
  def version
@@ -188,7 +226,7 @@ module Tor
188
226
  # S: 250 OK
189
227
  #
190
228
  # @example
191
- # tor.config_file #=> #<Pathname:/opt/local/etc/tor/torrc>
229
+ # tor.config_file #=> #<Pathname:/opt/local/etc/tor/torrc>
192
230
  #
193
231
  # @return [Pathname]
194
232
  def config_file
@@ -2,7 +2,7 @@ module Tor
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 1
5
+ TINY = 2
6
6
  EXTRA = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 1
9
- version: 0.1.1
8
+ - 2
9
+ version: 0.1.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Arto Bendiken
@@ -59,6 +59,7 @@ files:
59
59
  - README
60
60
  - UNLICENSE
61
61
  - VERSION
62
+ - lib/tor/config.rb
62
63
  - lib/tor/control.rb
63
64
  - lib/tor/dnsel.rb
64
65
  - lib/tor/version.rb