Skip to content
Browse files

Implemented a Tor configuration file parser.

  • Loading branch information...
1 parent 4702548 commit 87954d7fb1c82eb1cf7f45e89088a2c864281468 @bendiken committed Aug 2, 2010
Showing with 129 additions and 1 deletion.
  1. +20 −1 README.md
  2. +1 −0 lib/tor.rb
  3. +103 −0 lib/tor/config.rb
  4. +5 −0 spec/config_spec.rb
View
21 README.md
@@ -10,10 +10,13 @@ Features
* Supports checking whether Tor is installed in the user's current `PATH`,
and if it is, returning the version number.
+* Supports parsing Tor configuration files and looking up the values of
+ particular options.
* Supports querying and controlling a locally-running Tor process using the
[Tor Control Protocol (TC)][TC] over a socket connection.
* Supports querying the [Tor DNS Exit List (DNSEL)][TorDNSEL] to determine
whether a particular host is a Tor exit node or not.
+* Compatible with Ruby 1.8.7+, Ruby 1.9.x, and JRuby 1.4/1.5.
Examples
--------
@@ -26,7 +29,22 @@ Examples
Tor.available? #=> true
Tor.version #=> "0.2.1.25"
-### Obtaining information about a running Tor process
+### Parsing the Tor configuration file (1)
+
+ torrc = Tor::Config.load("/etc/tor/torrc")
+
+### Parsing the Tor configuration file (2)
+
+ Tor::Config.open("/etc/tor/torrc") do |torrc|
+ puts "Tor SOCKS port: #{torrc['SocksPort']}"
+ puts "Tor control port: #{torrc['ControlPort']}"
+ puts "Tor exit policy:"
+ torrc.each('ExitPolicy') do |key, value|
+ puts " #{value}"
+ end
+ end
+
+### Communicating with a running Tor process
Tor::Controller.connect(:port => 9051) do |tor|
puts "Tor version: #{tor.version}"
@@ -47,6 +65,7 @@ Dependencies
------------
* [Ruby](http://ruby-lang.org/) (>= 1.8.7) or (>= 1.8.1 with [Backports][])
+* [Tor](https://www.torproject.org/download.html.en) (>= 0.2.1)
Installation
------------
View
1 lib/tor.rb
@@ -17,6 +17,7 @@
##
# @see https://www.torproject.org/
module Tor
+ autoload :Config, 'tor/config'
autoload :Controller, 'tor/control'
autoload :DNSEL, 'tor/dnsel'
autoload :VERSION, 'tor/version'
View
103 lib/tor/config.rb
@@ -0,0 +1,103 @@
+module Tor
+ ##
+ # Tor configuration.
+ #
+ # @example Parsing a Tor configuration file (1)
+ # torrc = Tor::Config.load("/etc/tor/torrc")
+ #
+ # @example Parsing a Tor configuration file (2)
+ # Tor::Config.open("/etc/tor/torrc") do |torrc|
+ # puts "Tor SOCKS port: #{torrc['SocksPort']}"
+ # puts "Tor control port: #{torrc['ControlPort']}"
+ # puts "Tor exit policy:"
+ # torrc.each('ExitPolicy') do |key, value|
+ # puts " #{value}"
+ # end
+ # end
+ #
+ # @see https://www.torproject.org/tor-manual.html.en
+ # @since 0.1.2
+ class Config
+ CONFDIR = '/etc/tor' unless defined?(CONFDIR)
+
+ ##
+ # Opens a Tor configuration file.
+ #
+ # @param [String, #to_s] filename
+ # @param [Hash{Symbol => Object}] options
+ # @yield [config]
+ # @yieldparam [Config] config
+ # @return [Config]
+ def self.open(filename, options = {}, &block)
+ if block_given?
+ block.call(self.load(filename, options))
+ else
+ self.load(filename, options)
+ end
+ end
+
+ ##
+ # Loads the configuration options from a Tor configuration file.
+ #
+ # @param [String, #to_s] filename
+ # @param [Hash{Symbol => Object}] options
+ # @return [Config]
+ def self.load(filename, options = {})
+ self.new(options) do |config|
+ File.open(filename.to_s, 'rb') do |file|
+ file.each_line do |line|
+ case line = line.strip.chomp.strip
+ when '' then next # skip empty lines
+ when /^#/ then next # skip comments
+ else line = line.split('#').first.strip
+ end
+ # TODO: support for unquoting and unescaping values
+ config << line.split(/\s+/, 2)
+ end
+ end
+ end
+ end
+
+ ##
+ # @param [Hash{Symbol => Object}] options
+ # @yield [config]
+ # @yieldparam [Config] config
+ def initialize(options = {}, &block)
+ @lines, @options = [], options.dup
+ block.call(self) if block_given?
+ end
+
+ ##
+ # Appends a new configuration option.
+ #
+ # @param [Array(String, String)]
+ # @return [Config]
+ def <<(kv)
+ @lines << kv
+ self
+ end
+
+ ##
+ # Looks up the last value of a particular configuration option.
+ #
+ # @param [String, Regexp] key
+ # @return [String]
+ def [](key)
+ values = each(key).map(&:last)
+ values.empty? ? nil : values.last
+ end
+
+ ##
+ # Enumerates configuration options.
+ #
+ # @param [String, Regexp] key
+ # @yield [key, value]
+ # @yieldparam [String] key
+ # @yieldparam [String] value
+ # @return [Enumerator]
+ def each(key = nil, &block)
+ return enum_for(:each, key) unless block_given?
+ key ? @lines.find_all { |k, v| key === k }.each(&block) : @lines.each(&block)
+ end
+ end
+end
View
5 spec/config_spec.rb
@@ -0,0 +1,5 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+
+describe Tor::Config do
+ # TODO
+end

0 comments on commit 87954d7

Please sign in to comment.
Something went wrong with that request. Please try again.